I am trying to instanciate an object of a non public class in AspectJ.
I have this class:
package ca1.business;
public class Bill {
int id;
String idOperator;
String idClient;
Bill(int id, String idOperator, String idClient) { /* (...) */ }
public String toString() { /* (...) */ }
public boolean equals(Object o) { /* (...) */ }
public int getId() { /* (...) */ }
public String getOperator() { /* (...) */ }
public String getClient() { /* (...) */ }
}
In the aspects class I wanted to be able to do:
Bill b = new Bill(currInvoice, idOperator, idClient);
The problem is that I get an error:
The constructor Bill(int, String, String) is not visible
So I investigated and tried to use reflection like it's explained in this post.
try {
Constructor<Bill> cons = Bill.class.getDeclaredConstructor(null);
cons.setAccessible(true);
Bill invoice = cons.newInstance(null);
invoice.id = 1;
invoice.idOperator = "foo";
invoice.idClient = "bar";
// etc...
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
But I get an error in the lines:
invoice.id = 1;
invoice.idOperator = "foo";
invoice.idClient = "bar";
The error is:
The field Bill.X is not visible.
Does anyone know if there is any workaround?
Why use reflection?
Let us assume the Bill class looks like this:
package ca1.business;
public class Bill {
int id;
String idOperator;
String idClient;
Bill(int id, String idOperator, String idClient) {
this.id = id;
this.idOperator = idOperator;
this.idClient = idClient;
}
#Override
public String toString() {
return "Bill [id=" + id + ", idOperator=" + idOperator + ", idClient=" + idClient + "]";
}
public static Bill instance;
public static void main(String[] args) {
System.out.println(instance);
}
}
We want our aspect to populate the static member before main is executed (silly example, just for demo):
Option A: privileged aspect
package de.scrum_master.aspect;
import ca1.business.Bill;
public privileged aspect MyAspect {
before() : execution(public static void main(String[])) {
Bill.instance = new Bill(11, "operator", "client");
}
}
Option B: put aspect into package ca1.business
The constructor is package-private, i.e. other classes in the same package can access it.
package ca1.business;
public aspect MyAspect {
before() : execution(public static void main(String[])) {
Bill.instance = new Bill(11, "operator", "client");
}
}
Option C: put factory class into protected package as a helper
package ca1.business;
public class BillFactory {
public static Bill create(int id, String idOperator, String idClient) {
return new Bill(id, idOperator, idClient);
}
}
package de.scrum_master.aspect;
import ca1.business.Bill;
import ca1.business.BillFactory;;
public aspect MyAspect {
before() : execution(public static void main(String[])) {
Bill.instance = BillFactory.create(11, "operator", "client");
}
}
Console log for each option A, B, C
Bill [id=11, idOperator=operator, idClient=client]
Related
New to this topic and right now I'm stuck at a brick wall. I have 2 classes, parent class: Controller.java and subclass: GreenhouseControls.java. I need to serialize a GreenhouseControls object but also an instance variable (eventList) from its superclass Controller.java.
My serialization happens when an inner class of GreenhouseControls.java throws a custom ControllerException, which is caught in the main method. Before terminating the program, the GreenhouseControls object should be saved (including the field from its superclass).
Why is a NotSerializableException thrown by the inner class WindowMalfunction of GreenhouseControls? Anyone have any ideas, as I am seriously stuck?
What I tried is the following:
Implement serializable on Controller.java. This is because if the superclass is serializable, then subclass is automatically serializable, however this throws java.io.NotSerializableException: GreenhouseControls$WindowMalfunction, (WindowMalfunction is the inner class that throws the initial exception to begin the serialization processs).
Implement serializable on GreenhouseControls.java and implement custom serialization by overriding writeObject() and readObject() to save the field from the superclass. This approach yet again throws the same exception as the approach 1.
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(super.eventList);
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
Object obj = in.readObject();
List<Event> x = cast(obj);
super.eventList = x;
}
Controller.java
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
public class Controller {
// THIS IS THE VARIABLE I NEED TO SAVE
protected List<Event> eventList = new ArrayList<Event>();
public void addEvent(Event c) {
eventList.add(c);
}
public void run() throws ControllerException {
while (eventList.size() > 0)
// Make a copy so you're not modifying the list
// while you're selecting the elements in it:
for (Event e : new ArrayList<Event>(eventList))
if (e.ready()) {
System.out.println(e);
e.action();
eventList.remove(e);
}
}
public static void shutDown() { }
}
GreenhouseControls.java class (note I have removed the inner classes and other code from it and only left related info)
public class GreenhouseControls extends Controller implements Serializable {
private int errorcode = 0;
public class WindowMalfunction extends Event {
public WindowMalfunction(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
windowok = false;
throw new ControllerException("Window malfunction");
}
public String toString() {
return "Window malfunction";
}
}
public class PowerOut extends Event {
public PowerOut(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
poweron = false;
throw new ControllerException("Power out");
}
public String toString() {
return "Power out";
}
}
// Various other inner classes that extend event exist
public static void serializeObject(GreenhouseControls gc) {
FileOutputStream fileOut;
ObjectOutputStream out;
try {
fileOut = new FileOutputStream("dump.out");
out = new ObjectOutputStream(fileOut);
out.writeObject(gc);
System.out.println("WERRROR code: " + gc.getError());
out.close();
fileOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(super.eventList);
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
Object obj = in.readObject();
List<Event> x = cast(obj);
super.eventList = x;
}
#SuppressWarnings("unchecked")
public static <T extends List<?>> T cast(Object obj) {
return (T) obj;
}
public int getError() {
return errorcode;
}
public Fixable getFixable(int errorcode) {
switch (errorcode) {
case 1:
return new FixWindow();
case 2:
return new PowerOn();
default:
return null;
}
}
public static void main(String[] args) {
GreenhouseControls gc = null;
try {
String option = args[0];
String filename = args[1];
if (!(option.equals("-f")) && !(option.equals("-d"))) {
System.out.println("Invalid option");
printUsage();
}
// gc = new GreenhouseControls();
if (option.equals("-f")) {
gc = new GreenhouseControls();
gc.addEvent(gc.new Restart(0, filename));
}
gc.run();
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Invalid number of parameters");
printUsage();
} catch (ControllerException e) {
String errormsg;
if (e.getMessage().equals("Window malfunction")) {
gc.errorcode = 1;
errormsg = "Window malfunction event occurred Error code: " + gc.errorcode;
} else {
gc.errorcode = 2;
errormsg = "Power out event occurred Error code: " + gc.errorcode;
}
logError(errormsg);
serializeObject(gc);
gc.displayEventList();
shutDown();
}
}
}
Event.java
public abstract class Event {
private long eventTime;
protected final long delayTime;
public Event(long delayTime) {
this.delayTime = delayTime;
start();
}
public void start() { // Allows restarting
eventTime = System.currentTimeMillis() + delayTime;
}
public boolean ready() {
return System.currentTimeMillis() >= eventTime;
}
public abstract void action() throws ControllerException;
Event has to be Serializable too.
Change
public abstract class Event {
to
public abstract class Event implements Serializable {
I have some libraries from external company, I want to use this API. I try to implement calling this API, my logic should call the same method name. I have duplicate codes, I want to avoid to do this. I'm beginner and subjects like interfaces, polymorphism are little bit difficult to me.
public void modPeople(Object person)
{
if (person instanceof com.company.persontype1)
{
com.company.persontype1 fireman = (com.company.persontype1) person;
String name = fireman.getName();
if (name!=null ) {
...
fireman.set_name();
fireman.save();
}
permissions = fireman.get_Permissions();
...
permissions = fixperm (permissions);
fireman.set_Permissions();
};
if (person instanceof com.company.persontype2)
{
com.company.persontype2 nurse = (com.company.persontype2) person;
String name = nurse.getName();
if (name!=null ) {
...
nurse.set_name();
nurse.save();
}
permissions = nurse.get_Permissions();
...
permissions = fixperm (permissions);
nurse.set_Permissions();
};
}
First of all I should mention that the methodology which you requested in your question is called "Duck Typing". Generally this technology is possible in Java (see below the example) but it's not widely used in Java. There could be performance hits etc. It would be much better to introduce a proper inheritance/interface level instead.
Also the provided example don't deal with exceptions properly etc. It's just a quick and quite dirty "demostration of the technology". Feel free to adapt it for your needs.
It's Java7 (for multi-catch clauses, you may refactor this with ease).
ISomeIterface.java (it contains all common methods implemented by classes which are used in your "bad code"):
package org.test;
public interface ISomeInterface {
public String getName();
public void setName(String _name);
public void save();
// specify other common methods
}
ReflectCaller.java:
package org.test1;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import org.test.ISomeInterface;
public class ReflectCaller {
private final Method[] methods = ISomeInterface.class.getDeclaredMethods();
private final Map<Class<?>, Method[]> maps = new HashMap<Class<?>, Method[]>();
public void inspectClass(Class<?> _clazz) throws NoSuchMethodException, SecurityException {
final Method[] ms = new Method[methods.length];
int i = 0;
for(final Method m: methods) {
ms[i] = _clazz.getMethod(m.getName(), m.getParameterTypes());
i++;
}
maps.put(_clazz, ms);
}
public ISomeInterface wrapper(Object _obj) {
final Method[] ms = maps.get(_obj.getClass());
// To be replaced by guava's Preconditions.checkState()
if (ms == null)
throw new NoSuchElementException(String.format("Class %s is unregistered", _obj.getClass().getName()));
return new SomeInterfaceImpl(_obj, ms);
}
private static class SomeInterfaceImpl implements ISomeInterface {
private final Object obj;
private final Method[] ms;
public SomeInterfaceImpl(Object _obj, Method[] _ms) {
ms = _ms;
obj = _obj;
}
#Override
public String getName() {
try {
return (String) ms[0].invoke(obj);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
#Override
public void setName(String _name) {
try {
ms[1].invoke(obj, _name);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
#Override
public void save() {
try {
ms[2].invoke(obj);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
And test class ReflectTest.java. Notice that classes ReflectTest.Test and ReflectTest.Test2 has the same methods as ISomeInterface but don't implement it, they are completely independent from that interface and from each other.
package org.test2;
import org.test.ISomeInterface;
import org.test1.ReflectCaller;
public class ReflectTest {
private final ReflectCaller rc;
ReflectTest(Class ... _classes) throws NoSuchMethodException, SecurityException {
rc = new ReflectCaller();
for(final Class c: _classes)
rc.inspectClass(c);
}
void callSequence(Object _o) {
// this function demonstrates the sequence of method calls for an object which has "compliant" methods
ISomeInterface tw = rc.wrapper(_o);
tw.setName("boo");
System.out.printf("getName() = %s\n", tw.getName());
tw.save();
}
public static class Test {
public String getName() {
System.out.printf("%s.getName()\n", getClass().getName());
return "boo";
}
public void setName(String _name) {
System.out.printf("%s.setName(%s)\n", getClass().getName(), _name);
}
public void save() {
System.out.printf("%s.save()\n", getClass().getName());
}
}
public static class Test2 {
public String getName() {
System.out.printf("%s.getName()\n", getClass().getName());
return "boo2";
}
public void setName(String _name) {
System.out.printf("%s.setName(%s)\n", getClass().getName(), _name);
}
public void save() {
System.out.printf("%s.save()\n", getClass().getName());
}
}
public static void main(String[] args) {
ReflectTest rt;
try {
rt = new ReflectTest(Test.class, Test2.class);
} catch (NoSuchMethodException | SecurityException e) {
System.out.println(e);
System.exit(2);
return;
}
rt.callSequence(new Test());
rt.callSequence(new Test2());
}
}
I want to use the default JAX-RS response deserializer.
Here is my POJO
#JsonIgnoreProperties(ignoreUnknown = true)
public class Email
{
private String mFrom;
private List<String> mTo;
private List<String> mCc;
private List<String> mBcc;
private String mSubject;
private String mText;
public void setFrom(String from)
{
mFrom = from;
}
#JsonProperty("from")
public String getFrom()
{
return mFrom;
}
#JsonProperty("to")
public List<String> getTo()
{
return mTo;
}
public void setTo(List<String> to)
{
mTo = to;
}
#JsonProperty("carbon_copy")
public List<String> getCc()
{
return mCc;
}
public void setCc(List<String> cc)
{
mCc = cc;
}
#JsonProperty("blind_carbon_copy")
public List<String> getBcc()
{
return mBcc;
}
public void setBcc(List<String> bcc)
{
mBcc = bcc;
}
}
This my JAX-RS code.
#GET
#Produces("application/json", "application/xml", "text/xml")
public Response getEmails() {
List<Email> emails = getEmails(); //returns list of emails
return Response.ok(emails).build();
}
output
[{"from":"example#isp.com","to":[ ],"cC":[ ],"bCc":[ ],"subject":"my subject","text":"email from admin"}]
I want to change "cC" to the "carbon_copy". I want to solve this using the JAX-RS Response. How do I get JAX-RS to use the jackson annotated property name. Do I need to override something?
My current implementation i did the following.
public class JsonDeserializer
{
private static ObjectMapper mMapper;
static
{
mMapper = new ObjectMapper();
mMapper.setSerializationInclusion(Inclusion.NON_NULL);
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> T fromInputStream(InputStream is, Class t)
{
try
{
return (T) mMapper.readValue(is, t);
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ClassCastException e)
{
e.printStackTrace();
}
return null;
}
}
Response.ok(JsonDeserializer.toJson(emails)).build();
Is there away to do it without creating another class to handle the deserialization process.
Mix-in can help you resolve this. You need to create an abstract class say "EmailExpanded" that has the property something like this:
#JsonProperty("carbon_copy")
public abstract List<String> getCc();
Then add that mixin:
emailExpandMapper = new ObjectMapper();
emailExpandMapper.getSerializationConfig().addMixInAnnotations(
Email.class, EmailExpanded.class);
emailExpandMapper.getSerializationConfig().setSerializationInclusion(
Inclusion.NON_NULL);
Later in the code while you send the response:
emailExpandMapper.writeValueAsString(emails)
You can read more about Mixins in the web.
Maybe I missunderstood JavaFX binding or there is a bug in SimpleStringProperty.
When I run this testcode my changed model value didn't get the new value. Test testBindingToModel fails. I thought my model should then be updated with the value of the TextField tf. But only the binding value of prop1Binding gets the value "test".
public class BindingTest {
private TextField tf;
private Model model;
private ModelBinding mb;
#Before
public void prepare() {
tf = new TextField();
model = new Model();
mb = new ModelBinding(model);
Bindings.bindBidirectional(tf.textProperty(), mb.prop1Binding);
}
#Test
public void testBindingToMB() {
tf.setText("test");
assertEquals(tf.getText(), mb.prop1Binding.get());
}
#Test
public void testBindingToModel() {
tf.setText("test");
assertEquals(tf.getText(), mb.prop1Binding.get());
assertEquals(tf.getText(), model.getProp1());
}
private static class ModelBinding {
private final StringProperty prop1Binding;
public ModelBinding(Model model) {
prop1Binding = new SimpleStringProperty(model, "prop1");
}
}
private static class Model {
private String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
}
}
Thanks for your help.
Best regards
Sebastian
EDIT:
With this class I can set the value of the model directly. I will test this class in the next days and comment on this post with my result.
public class MySimpleStringProperty extends SimpleStringProperty {
public MySimpleStringProperty(Object obj, String name) {
super(obj, name);
}
public MySimpleStringProperty(Object obj, String name, String initVal) {
super(obj, name, initVal);
}
#Override
public void set(String arg0) {
super.set(arg0);
if (this.getBean() != null) {
try {
Field f = this.getBean().getClass().getDeclaredField(this.getName());
f.setAccessible(true);
f.set(this.getBean(), arg0);
} catch (NoSuchFieldException e) {
// logging here
} catch (SecurityException e) {
// logging here
} catch (IllegalArgumentException e) {
// logging here
} catch (IllegalAccessException e) {
// logging here
}
}
}
}
This constructor doesn't attach SimpleStringProperty to a bean object unfortunately. It just says to SimpleStringProperty which bean property belongs to.
E.g., if you want to have a property in your class you should do it next way:
public static class Model {
private StringProperty prop1 =
new SimpleStringProperty(this, "prop1", "default_value");
public String getProp1() {
return prop1.get();
}
public void setProp1(String value) {
prop1.set(value);
}
public StringProperty prop1Property() {
return prop1;
}
}
Note, that there is no way to bind to your original Model class as it provides no events about setting new prop1 value. If you want to have observable model, you should use fx properties from the beginning.
Just figured out that there is provided the class JavaBeanStringProperty, which just fullfill my request.
Using this code I can directly bind the value of my bean to a StringProperty (included setting and getting of my value to / from my Bean).
binding = JavaBeanStringPropertyBuilder.create().beanClass(Model.class).bean(model).name("prop1").build();
The only problem I found is that when you change the value of the model after setting the binding, there is no update e.g. in the TextField.
I want to implement a sort of transfer object pattern. So, i have a method that fills object´s properties via BeanUtils.copyProperties(..,..) (apache common).
Here is the code:
public abstract class BaseTO<TObject> {
public Long id;
/***
* Obtains id of the object that´s transfered
* #return object´s id
*/
public Long getId() {
return id;
}
/****
* set transfered object´s id
* #param id object´s id
*/
public void setId(Long id) {
this.id = id;
}
/***
* Fill transfer object properties.
* #param entity entity to be transfered
* #return self reference
*/
public BaseTO<TObject> build(TObject entity){
try {
BeanUtils.copyProperties(this, entity);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
customDataTransformation(entity);
return this;
}
protected void customDataTransformation(TObject entity) {
}
}
CustomerTO Class
public class CustomerTO extends BaseTO<Customer> {
private String name;
private String surname;
private String email;
private String sex;
private DocumentType documentType;
private String documentNumber;
--- getters and setters
#Override
protected void customDataTransformation(Customer entity) {
this.sex = Sex.MALE.equals(entity.getSex()) ? "M" : "F";
}
}
the problem
CustomerTO toEdit = (CustomerTO) (customerId!=null ? new CustomerTO().build(entityObject):new CustomerTO());
as you can see here have to cast to (CustomerTO). I want if it´s possible avoid that, to make the code simpler.
Is it posible that public BaseTO build(TObject entity) can return the object of the subclass??
I hope to be clear.
Thanks in advance.
Maybe try this:
class BaseTO<TObject, R extends BaseTO<TObject,R>> {
public R build(TObject entity) {
and then CustomerTO:
class CustomerTO extends BaseTO<Customer, CustomerTO> {
or less restrictively, only change the build signature:
public <X extends BaseTO<TObject>> X build(TObject entity) {
But IMHO better approach will be simply adding constructor to TO with TObject parameter.
public BaseTO(TObject entity) {
try {
BeanUtils.copyProperties(this, entity);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
customDataTransformation(entity);
}
then in each extending class create simple constructor
public CustomerTO(Customer entity) {
super(entity);
}
and forget about the build method and use it simply
CustomerTO toEdit = (customerId!=null ? new CustomerTO(entityObject):new CustomerTO());
This compiles:
public class BaseTO<T> {
public BaseTO<T> build(T entity) {
return this;
}
public static class CustomerTO extends BaseTO<String> {
#Override public CustomerTO build(String string) {
return (CustomerTO) super.build(string);
}
}
but you will have to override build for all subclasses of BaseTO. You write explicitly the cast only once instead of every time you call build.
EDIT: see the point raised by #Paul in the comments above. You might be suffering from "give a man a hammer and everything looks like a nail to him."