I need to create and populate an object inside a method. The only information is the member field name (passed as a string) and the relevant value for that field (passed as an Object). What is the most appropriate design pattern taking into account performance? - reflection, if comes with a penalty, would not be a preferred approach.
Update:
The value to be set comes from an object that acts as a generator of the values having a set of methods that return the proper value for the specific field. E.g. for member Double x; it would be generator.getX()
A simple function to copy all the getters to all the available setters is as follows. With some more work you can cache this information and speed it up but it is likely to be fast enough as it is.
public static <T> T copyTo(Object from, T to) {
for(Method m : to.getClass().getMethods()) {
if (!m.getName().startsWith("set") || m.getParameterCount() != 1)
continue;
try {
Method getter = from.getClass().getMethod("g" + m.getName().substring(1));
m.invoke(to, getter.invoke(from));
} catch (NoSuchMethodException ignored) {
// ignored
} catch (InvocationTargetException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
return to;
}
Note: Only the fields where there is a matching getter and setter will attempt to copy from one to the other.
public static void main(String[] args) {
One orig = new One(1, "hi", 3);
One to = new One();
One copy = copyTo(orig, to);
System.out.println(to);
}
static class One {
int x;
String y;
double z;
public One() {
}
public One(int x, String y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
#Override
public String toString() {
return "One{" +
"x=" + x +
", y='" + y + '\'' +
", z=" + z +
'}';
}
}
prints
One{x=1, y='hi', z=3.0}
If you want to create an object generically you need to use reflection.
The only alternative is byte code generation which will be much more complex to implement and only save you a fraction of a micro-second.
How many days is it worth sending to implement this to save a micro-second?
If you know the class name of the object then what you can do is:
public Object populate(String className,String fieldName,Object value) throws Exception{
Class clazz = Class.forName(className);
Object o = null;
for(Field f: clazz.getFields()){
if(f.getName().equals(fieldName)){
o = clazz.getConstructor().newInstance();//default constructor if it exists
f.set(o, value);
break;
}
}
return o;
}
EDIT:
Since you know the class(comment under question) then you can use is the function I wrote just with this change and not className parameter:
Class clazz = Class.forName(YourClass.class.getName());
EDIT2:
If I understand the update you are asking about how to know which method to invoke to get the value.
On your generator class you can get the list of methods it has. Then if your method are named getFieldName() you can once you have the field name find the method with the name getFiledName.
Example:
for(Method m:GeneratorClass.class.getMethods()){
System.out.println(m.getName());
//analyze method name and field name to determine which method to call
//..
boolean callThis = true;//result of analysis
if(callThis){
//Object value = m.invoke(obj);
//obj==generator
}
}
Related
Interface:
public interface SomeInt{
Integer getX();
void setX(Integer value);
default Integer getY(){
return getX();
}
default void setY(Integer value){
setX(value);
}
}
A Class implement it:
public class A implements SomeInt{
private Integer x;
public Integer getX(){
return x;
}
public void setX(Integer value){
x = value;
}
}
When initialized, I can call the method getY & setY, and get the right return.
But I cannot use it in JSP(EL), like ${instance_of_class_a.y}. And the property Y is not list in IDEA's variables list(Debug Mode).
If I do add the getY & setY explicitly in class A, everything is ok.
Why? I think default method is like a compiler sugar.
Sorry for my poor english and the mistakes in the code, I've correct it.
The question is a bit ill written here, so maybe something went wrong.
Especially add #Override for typos.
interface SomeInt {
int getX();
void setX(int x);
default int getY() {
return getX();
}
default void setY(int value) {
setX(value);
}
}
static class A implements SomeInt {
private int x;
#Override
public int getX() {
return x;
}
#Override
public void setX(int value) {
x = value;
}
}
System.out.println("Methods:");
for (Method m : A.class.getMethods()) {
System.out.printf("+ %s%n", m.getName());
}
for (Method m : A.class.getDeclaredMethods()) {
System.out.printf("- %s%n", m.getName());
}
In general for getters/setters Class.getMethods is used.
Methods:
+ setX
+ getX
...
+ setY
+ getY
- setX
- getX
I think I've got the answer.
BeanELResover using java.beans.Introspector to getBeanInfo(Properties)
public static BeanInfo getBeanInfo(Class<?> beanClass)
throws IntrospectionException
{
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (declaredMethodCache) {
beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (declaredMethodCache) {
context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
}
The constructor of Introspector call a method "findExplicitBeanInfo" to getDeclaredMethods of current class. Then do it with its superClass until Object or stopClass. The method of interfaces will not be loaded here.
private Introspector(Class<?> beanClass, Class<?> stopClass, int flags)
throws IntrospectionException {
this.beanClass = beanClass;
// Check stopClass is a superClass of startClass.
if (stopClass != null) {
boolean isSuper = false;
for (Class<?> c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
if (c == stopClass) {
isSuper = true;
}
}
if (!isSuper) {
throw new IntrospectionException(stopClass.getName() + " not superclass of " +
beanClass.getName());
}
}
if (flags == USE_ALL_BEANINFO) {
explicitBeanInfo = findExplicitBeanInfo(beanClass);
}
Class<?> superClass = beanClass.getSuperclass();
if (superClass != stopClass) {
int newFlags = flags;
if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
newFlags = USE_ALL_BEANINFO;
}
superBeanInfo = getBeanInfo(superClass, stopClass, newFlags);
}
if (explicitBeanInfo != null) {
additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
}
if (additionalBeanInfo == null) {
additionalBeanInfo = new BeanInfo[0];
}
}
After running a Junit test for user-defined object serialization, it was failed and gave me the results
Expected: com.me.Position#7a92922
Actual: com.me.Position#25618e91
I have defined the following class
public class Position {
private double x;
private double y;
/**
* default constructor
*/
public Position() {
}
/**
* paramterized constructor
*
* #param x
* x-coordinate
* #param y
* y-coordinate
*/
public Position(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
then I defined another class to serialize and deserialize a Position object which is an instance of the previous class as following
public class PositionSerializer {
static void serialize(Position position, OutputStream outputStream) {
OutputStreamUtil.serializeDouble(position.getX(), outputStream);
OutputStreamUtil.serializeDouble(position.getY(), outputStream);
}
static Position deserialize(InputStream inputStream) {
double x = InputStreamUtil.deserializeDouble(inputStream);
double y = InputStreamUtil.deserializeDouble(inputStream);
Position positionObject = new Position();
positionObject.setX(x);
positionObject.setY(y);
return positionObject;
}
}
Finally, I wrote a unit test as follows
public class PositionSerializerTest {
private InputStream iStream;
private ByteArrayOutputStream oStream;
#Before
public void init() {
oStream = new ByteArrayOutputStream();
}
Position serialzeAndDeserializeObject(Position positionObject) {
PositionSerializer.serialize(positionObject, oStream);
iStream = new ByteArrayInputStream(oStream.toByteArray());
return PositionSerializer.deserialize(iStream);
}
#Test
public void equals_equal() {
Position positionObject = new Position(5.5, 10.5);
Position deserializedPosition = serialzeAndDeserializeObject(positionObject);
assertThat(deserializedPosition).isEqualTo(positionObject);
}
}
what was wrong? and how to fix it?
You are checking reference equality which is not equal because your deserialize method returns new instance on every call, use below for comparing values :
assertThat(deserializedPosition.getX()).isEqualTo(positionObject.getX())
assertThat(deserializedPosition.getY()).isEqualTo(positionObject.getY())
There is nothing wrong,but you are creating a new instance in deserialize method:
Position positionObject = new Position();
This will always call new instance of Position Object and hence you can not compare it using == operator
You should override equals method as below:
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Position)) {
return false;
}
Position otherObject = (Position)o;
if(this.x == otherObject.x && this.y == otherObject.y)
return true;
else return false;
}
And then call :
assertThat(deserializedPosition).isEqualTo(positionObject);
It looks like your test is comparing the object references and not the object values. Override the equals function or compare each value in the position object separately.
My class details attributes of restaurants downtown, said attributes being x/y locations and rank. The problem is, whenever I run the program It throws an error, saying that non-abstract class "Downtown" does not override abstract method "compareTo". I cannot make this class abstract because I need to initialise the object outside this block of code. Where does my program go wrong? Is there a problem with my compareTo implementation? Any suggestions will be much appreciated.
public class Downtown implements Comparable<Downtown> {//Throws error on this line
private int x;
private int y;
private int rank;
public Downtown(int x, int y, int rank) {
this.x = x;
this.y = y;
this.rank = rank;
}
//Appropriate setters and getters for x , y and rank
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public int compareTo(Downtown p1, Downtown p2)//Actual comparison
{
// This is so that the sort goes x first, y second and rank last
// First by x- stop if this gives a result.
int xResult = Integer.compare(p1.getX(),p1.getX());
if (xResult != 0)
{
return xResult;
}
// Next by y
int yResult = Integer.compare(p1.getY(),p2.getY());
if (yResult != 0)
{
return yResult;
}
// Finally by rank
return Integer.compare(p1.getRank(),p2.getRank());
}
#Override
public String toString() {
return "["+x+' '+y+' '+rank+' '+"]";
}
Java's Comparable<T> interface defines compareTo method as follows:
int compareTo(T o);
This means that the method must take one parameter; the other parameter is the object itself, i.e. this. You need to implement this one-argument method in place of your two-argument method to fix this problem.
Compiler will help you figure out issues like this by using #Override annotation on your method:
#Override // Issues an error
public int compareTo(Downtown p1, Downtown p2)
#Override // Compiles fine
public int compareTo(Downtown other)
The compareTo method should compare the current object (this) to just one other. It shouldn't have two parameters for comparison. You could write your method like this.
public int compareTo(Downtown p2)//Actual comparison
{
// This is so that the sort goes x first, y second and rank last
// First by x- stop if this gives a result.
int xResult = Integer.compare(getX(),p2.getX());
if (xResult != 0)
{
return xResult;
}
// Next by y
int yResult = Integer.compare(getY(),p2.getY());
if (yResult != 0)
{
return yResult;
}
// Finally by rank
return Integer.compare(getRank(),p2.getRank());
}
Notice how I've replace all the calls on p1 to calls on the current object.
is it possible to get the final parameter values from an anonymous class? Using reflection or anything else?
This example is of course all made up:
final String x = "Param1";
final String y = "Param2";
ITest<String> iTest = new ITest<String>() {
#Override
public String execute() {
return t.testMethod(x, y);
}
};
// Get values or x and y from iTest here?
So this is your code:
ITest<String> iTest = new ITest<String>() {
#Override
public String execute() {
return testMethod(x, y);
}
};
Try defining ITest like so:
public class ITest {
int x;
int y;
public testMethod(int x, int y) {
this.x = x; this.y = y;
}
// execute somewhere
}
I haven't tried this myself, but I believe that the values of x and y are copied into autogenerated fields in the anonymous class instance. Try this:
for (Field field : iTest.getClass().getDeclaredFields()) {
field.setAccessible(true);
System.out.println(field.getName() + ": " + field.get(iTest));
}
Consider a wrapper class W, wrapping C, this meaning that for most attributes of C, there is a correspondent attribute A on W, its logic consisting in nothing more than delegation to C's A. This situation can be most precisely depicted with the sketch shown below:
class W {
private C c;
getX() { return c.getX(); }
getY() { return c.getY(); }
}
The trouble is that I've decided that I wan't to get rid of getX(), and I'd prefer to either as a transitory step to put C c as public, having all the calling code of W do a w.c.getX() or w.c.getY() or alternatively to put create a W.getC(), and have all calls to getX() and getY() go through it.
What this all boils down is to an "un-encapsulate" refactoring. Is there anything performing this much needed task either in Eclipse or Intellij?
With IntelliJ you can use the Remove Middleman refactoring.
Consider:
Before:
public class W {
private C c;
Object getX() { return c.getX(); }
Object getY() { return c.getY(); }
}
public class C {
private Object x;
private Object y;
public Object getX() {
return x;
}
public Object getY() {
return y;
}
}
public class UsesW {
W w;
public void useW() {
Object x = w.getX();
Object y = w.getY();
}
}
Place your cursor on the declaration of W.c. Then choose Refactor | Remove Middleman.
The result gets you halfway to where you want to be:
After:
public class W {
private C c;
public C getC() {
return c;
}
}
/* class C is unchanged */
public class UsesW {
W w;
public void useW() {
Object x = w.getC().getX();
Object y = w.getC().getY();
}
}
Then you can introduce a variable of type C in UsesW. Place your cursor over one of the calls to w.getC() and inline it: Refactor | Inline... (Ctrl-Alt-N is the default shortcut), choosing to inline all instances. It'll leave you with this:
public class UsesW {
W w;
public void useW() {
final C c = w.getC();
Object x = c.getX();
Object y = c.getY();
}
}
Finally getting rid of W altogether is something you probably can answer better than me, but now that job became significantly easier.
Write your new getC() method.
Rewrite getX() to be return getC().getX().
Inline getX().
The same goes for y.