Copy data to same classes in different packages - java

I am calling an external service that returns the following class:
package abc;
public class FirstClass {
private String name;
private String age;
private String number;
}
In my model, I have defined a class with same structure:
package xyz;
public class FirstClass {
private String name;
private String age;
private String number;
}
I want to copy data from the abc.FirstClass object to xyz.FirstClass object. I don't want to map the data field by field. I think it can be done by dozer - are there any easier methods to do it?

You could use PropertyUtils#copyProperties:
Copy property values from the "origin" bean to the "destination" bean for all cases where the property names are the same (even though the actual getter and setter methods might have been customized via BeanInfo classes).
Example:
abc.FirstClass src = new abc.FirstClass();
xyz.FirstClass dest = new xyz.FirstClass();
PropertyUtils.copyProperties(dest, src);

The reason you cannot copy the entire class object is because each class object has unique hashcode. Even if your class has same attribute.
I know it is a pain but mapping by field is the only way to go.
You can try use spring beans to help map the fields.

Java Reflection is the way to go.
From The Java™ Tutorials
A field is a class, interface, or enum with an associated value. Methods in the java.lang.reflect.Field class can retrieve information about the field, such as its name, type, modifiers, and annotations. There are also methods which enable dynamic access and modification of the value of the field
Try something like this:
StackOverflow.abc.firstClass abc = new StackOverflow.abc.firstClass();
StackOverflow.xyz.firstClass xyz = new StackOverflow.xyz.firstClass();
Class<? extends StackOverflow.xyz.firstClass> xyzClass = xyz.getClass();
Field[] fields = abc.getClass().getDeclaredFields();
for (Field abcField : fields) {
abcField.setAccessible(true); //To access private fields
try {
Field xyzField = xyzClass.getDeclaredField(abcField.getName());
xyzField.setAccessible(true);
xyzField.set(xyz, abcField.get(abc));
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
You can check out this tutorial from Oracle for more details. Or, specifically this page from the tutorial.

You can using reflection
this does the job and shows it:
public class FirstClass {
private String name;
private String age;
private String number;
public FirstClass(String _name, String _age, String _number)
{
name=_name; age=_age; number=_number;
}
}
public class CloneClass {
private String name;
private String age;
private String number;
public CloneClass(String _name, String _age, String _number)
{
name=_name; age=_age; number=_number;
}
public void show()
{
System.out.println("NAME="+name+" AGE="+age+" NUMBER="+number);
}
}
FirstClass A=new FirstClass("Jules","44","123A4535");
CloneClass B=new CloneClass("","","");
Class class1=A.getClass();
Class class2=B.getClass();
// all fields from A
Field[] fields_A = class1.getDeclaredFields();
Field[] fields_B = class2.getDeclaredFields();
for (int k=0;k<fields_A.length;k++)
{
Field one_field=fields_A[k];
// Name of field in source
String name_of_field=one_field.getName();
if (name_of_field.equals("this$0")) continue; // Not this !
// Search if it exists in destination
for (int z=0;z<fields_B.length;z++)
{
Field field_destination=fields_B[k];
String name_of_field2=field_destination.getName();
if (name_of_field.equals(name_of_field2))
// TODO
// You should also verify the type !
{
try
{
// To read private var
one_field.setAccessible(true);
field_destination.setAccessible(true);
Object value=one_field.get( A);
field_destination.set(B, value);
}
catch (Exception ex) {System.err.println(ex);}
}
}
} // for (int k=0;k<fields_A.length;k++)
B.show();

Related

inherited java ArrayList to JSON

I have a class that overrides ArrayList like:
public class SkmeList extends ArrayList<SkmeStatement> {
private static final long serialVersionUID = 1L;
private int skmeMajor = 0;
private int skmeMinor = 0;
private String skmeTable = null;
public void setTable(String table) {
System.out.println("Set Table: " + table);
skmeTable = table;
}
public String getTable() {
return skmeTable;
}
public void setMajor(int major) {
System.out.println("SetMajor: " + major);
skmeMajor = major;
}
public int getMajor() {
return skmeMajor;
}
public void setMinor(int minor) {
System.out.println("SetMinor: " + minor);
skmeMinor = minor;
}
public int getMinor() {
return skmeMinor;
}
}
when I attempt to write this class to a file or even a string using jackson I can only see the list contents, I do not see any of class specific attributes like Major or minor in the string/file? I treat this class just like any other java class. Is there something that is different with lists in jackson object mapper?
public void WriteJson(SkmeList statements) {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(out, statements);
final byte[] data = out.toByteArray();
System.out.println(new String(data));
}
catch (IOException ioe) {
System.out.println("Foo");
}
}
A List has elements and no further non-element data. If you need more data, you need something that's more than a List.
The user of your class already has to treat it specially if they care about any of the extra fields you've added.
In favoring composition over inheritance, here's how I'd suggest this class could look like.
public class SkmeList {
private final int major;
private final int minor;
private final String table;
private final List<SkmeStatement> statements;
// ctor, getters, hashCode, equals and toString omitted
}
With more context on what Skme means, we could make the naming even clearer.
To make it easier to reason about, the class should be immutable, to make it safe for use in a Collection it should have hashCode() and equals(), and a toString() in case it ever gets printed/logged/debugged around.
If you don't feel like implementing all the omitted methods, consider AutoValue: you specify the getters and a factory method, the rest is generated for you.
For the user of your class, it's almost the same:
SkmeList list = ...
for (SkmeStatement stmt : list) {
...
now becomes
SkmeList list = ...
for (SkmeStatement stmt : list.getStatements()) {
...

Check if class has a variable in its constructor based on a string?

Let's say I have a class named Person and its constructor had variables like name, age, hairColor and so on. If I had a function that receives a string that should match one of the class's variables, how could I check if that class actually had that variable and how could I go about modifying it? For example:
public class Person {
public String name;
public int age;
public String hairColor;
public Person() {
name = "Bryce";
age = 21;
hairColor = "brown";
}
public void changeHairColor(String variable, String color) {
if (/*this class contains the variable passed as an argument to this method*/) {
// Person[variable] = color
}
}
}
I'm a python dev, mostly, so the method changeHairColor has some pseudo-python in it. I want to be able to edit the variable in a similar way you could edit variables inside of dictionaries with Python:
person = {
"name": "Bryce",
"age": 21,
"hairColor": "brown"
}
def changeHairColor(variable, color):
person[variable] = color
If that is at all possible.
The only way to do it in Java is to use Java Reflection API:
public class Test {
public String name;
public int age;
public String hairColor;
public void setProperty(String property, Object value) {
try {
Field declaredField = this.getClass().getDeclaredField(property);
switch (declaredField.getAnnotatedType().getType().getTypeName()) {
case "java.lang.String":
declaredField.set(this, value);
break;
// handle other types
}
} catch (NoSuchFieldException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
}
public static void main(String[] args) {
Test test = new Test();
test.setProperty("name", "Bob");
System.out.println(test.name);
}
}
I would not solve this with reflection. If your PlayerCharacter has an enumerable set of attributes, I would model these as a Java enum and store the attribute values within the PlayerCharacter object in an EnumMap:
import java.util.EnumMap;
public class PlayerCharacter {
public enum Attribute {
AGILITY,
DEXTERITY,
/* etc ...*/
VITALITY
}
private EnumMap<Attribute, Integer> attributes = new EnumMap<>(Attribute.class);
public PlayerCharacter() {
// initialize each attribute with a default value (0 in this example)
for (Attribute a : Attribute.values()) {
attributes.put(a, new Integer(0));
}
}
public int getValue(Attribute attribute) {
return attributes.get(attribute);
}
public void levelUp(Attribute attribute, int amount) {
attributes.put(attribute, attributes.get(attribute) + amount);
}
}
The biggest benefit of using an enum instead of plain old String (+reflection), is that this way you get compile-time type safety for the code that's using your PlayerCharacter.
Using Reflection API, you can access the methods and properties on an object at run time. The other answer describes its usage. But I don't recommend reflections for your problem. How about the following:
public void changeHairColor(String variable, String color) {
if("name".equalsIgnoreCase(variable))
this.name = color;
else if("age".equalsIgnoreCase(variable))
this.age = Integer.parseInt(color);
else if("color".equalsIgnoreCase(variable))
this.color = color;
else
throw new Exception ("error - property not available");
}
}
Note, your existing method name 'changeHairColor' doesn't make sense in the context. It should be someething like 'changeProperty' because you are not just changing the 'color', you are changing any available property with this method.

Jackson won't wrap class

I have a class that holds contact data; wrapped in a respective class. I recently changed my Photo setup from being a simple byte[] to being a wrapped class as well, but the instantitaion is a little different and now won't serialize/wrap properly.
My other classes wrap properly such as "number":{"log.PhoneNumber":{"number":"123-456-7890"}} but if I feed in a new photo (ie: new Photo("DEADBEEF")) I just get "photo":"DEADBEEF". This is causing problems with the deserializer too.
public class ContactInfo {
#JsonProperty("name") private Name m_name = null;
#JsonProperty("number") private PhoneNumber m_number = null;
#JsonProperty("email") private Email m_email = null;
#JsonProperty("photo") private Photo m_photo = null;
#JsonCreator
public ContactInfo(#JsonProperty("name") Name name,
#JsonProperty("number") PhoneNumber number,
#JsonProperty("email") Email email,
#JsonProperty("photo") Photo photo) {
/** Set vars **/
}
#JsonTypeInfo(use=Id.CLASS, include=As.WRAPPER_OBJECT)
static public class Photo {
private byte[] m_decodedBase64 = null;
public Photo(byte[] encodedBase64) {
m_decodedBase64 = Base64.decodeBase64(encodedBase64);
}
#JsonCreator
public Photo(#JsonProperty("photoData")String encodedBase64) {
m_decodedBase64 = Base64.decodeBase64(encodedBase64);
}
#JsonProperty("photoData")
public String getEncodedPhoto() {
return Base64.encodeBase64String(m_decodedBase64);
}
public byte[] getDecodedData() {
return m_decodedBase64;
}
}
}
What am I doing wrong?
Just figured out what it was. In the ContactInfo class there was a simple accessor function to get the encodedData.
public String getPhoto() {
return m_photo.getEncodedPhoto();
}
By simple putting it on ignore (or simply change it to return the object itself, which I might do),
#JsonIgnore
public String getPhoto() {
return m_photo.getEncodedPhoto();
}
The serializer stopped trying to read from it. I wish there was a way to set the serializer engine to be more "explicit declaration" for properties instead of "serialize everything that seems to match the member variables."

Remove key and value from object

My data model is as follow:
public class CustomerObject implements Serializable
{
public Integer pkid;
public String code;
public String name;
public CustomerObject()
{
pkid = new Integer(0);
code = "";
name = "";
}
}
Now I am calling this from another class:
public CustomerObject getCustObj() {
CustomerObject custObj = new CustomerObject();
custObj.pkid = new Integer(1001);
custObj.code = "CUST1001";
return custObj;
}
Now here in getCustObj() function I want to pass only pkid and code. I mean I want to remove the variable "name" from the object and then pass. So my passing object will look like:
CustomerObject()
{
pkid = 1000;
code = CUST1001;
}
Please help how I can do this.
Actually I have a data model of 200 variable. I will pass this using webservice. But during pass by webservice I may need only 20 to pass. So I want to reduce the data size.
Use another constructor in class CustomerObject as following.
public class CustomerObject implements Serializable
{
public Integer pkid;
public String code;
public String name;
public CustomerObject()
{
pkid = new Integer(0);
code = "";
name = "";
}
public CustomerObject(int inPkid, String inCode)
{
this.pkid = inPkid;
code = inCode;
}
}
When you call getCustomerObject method from another class use as follows
public CustomerObject getCustObj() {
CustomerObject custObj = new CustomerObject(new Integer(1001),"CUST1001");
}
If you are not setting name in your object, then it is as good as object not having name because name is null. You can't remove name variable from the object.
But if you really want to do so, you can use inheritance. Make one class with all attributes except name and other class extends the first class and adds name attribute to it. So now you can use first class when you don't need the name attribute.

java - an enum question

I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx

Categories