How to Parse Json generic array with inheritance items - java

my question is not same is this question.
if i want to explain lets assume we have these classes (A, B, C).
#Data
#NoArgsConstructor
class A {
private Integer x;
private String type;
public A(String type, Integer x) {
this.type = type;
this.x = x;
}
}
#Data
class B extends A {
private Integer y;
public B(Integer x, Integer y) {
super("B", x);
this.y = y;
}
}
#Data
class C extends A {
private Integer z;
public C(Integer x, Integer z) {
super("C", x);
this.z = z;
}
}
know i want to parse an array which their base classes is A. and with property named type i want to convert each item to its specific class.
something like this code.
public static void main(String[] args) {
Gson gson = new Gson();
List<A> list = new ArrayList<>();
A a = new A("A", 0);
list.add(a);
B b = new B(1, 2);
list.add(b);
C c = new C(3, 4);
list.add(c);
String serializedJson = gson.toJson(list);
List<? extends A> deserializedList = gson.fromJson(serializedJson, new TypeToken<List<? extends A>>() {
}.getType());
for (A item : deserializedList) {
System.out.println(item.getType());
if (item instanceof B) {
System.out.println(((B) item).getY());
} else if (item instanceof C) {
System.out.println(((C) item).getZ());
}
}
}
serialized json is something like this
[{"x":0,"type":"A"},{"y":2,"x":1,"type":"B"},{"z":4,"x":3,"type":"C"}]
in real world, i have something like this json and want to parse it.
but when i run the code y and z properties not printed and objects are not instance of B or C.
how to achieve to this goal to parse and create each item with type property.

I found the solution via Gson TypeAdapterFactory mechanism.
creating a class to implement com.google.gson.TypeAdapterFactory. for more detail see this link

for(A item : deserializedList) {
switch(item.getType()) {
case "B":
System.out.println(((B) item).getY());
break;
case "C":
System.out.println(((C) item).getZ());
break;
}
}

Related

Storing Objects of multiple classes in an Array List, then accessing their attributes

I have class of (sub)Objects
public class SubObjects {
int depth;
public SubObjects(int d) {
this.depth = d;
}
}
And a class of Objects
public class Objects {
private int height;
private int width;
ArrayList<SubObjects> liste;
public Objects(int h, int w) {
this.height = h;
this.width = w;
this.liste = new ArrayList<>();
}
}
The Objects hold the values height and width and an ArrayList of SubObjects. This works as intended, I do however want to store multiple types of SubObjects from different classes in these ArrayLists.
After a bit of googling I changed the Objects class to
public class Objects {
private int height;
private int width;
ArrayList<Object> liste;
public Objects(int h, int w) {
this.height = h;
this.width = w;
this.liste = new ArrayList<Object>();
}
}
This allows me, as I intended, to store Objects from a second class SubObjects2 inside the ArrayList
public class SubObjects2 {
int weight;
public SubObjects2(int weight) {
this.weight = weight;
}
}
This was great and I thought I had solved it, but then I ran the main class and while I, with the earlier implementation could return values with a getter from the objects in the ArrayList
... liste.get(i).depth (in a for loop)
The same query now returns the following error
Unresolved compilation problem:
depth cannot be resolved or is not a field
How do I access the values inside the SubObjects that are stored in the ArrayList now?
Your problem is that the Object class has no field with the name depth and only SubObject has this attribute
If all of your types have common attributes that you want to get it, you can create an interface and all of them should implement it it for example
interface SubObject {
int value();
}
public class SubObjects implements SubObject {
...
#Override
public int value() {
return depth;
}
}
public class SubObjects2 implements SubObject {
...
#Override
public int value() {
return weight;
}
}
and now you will create a list of SubObject and in the loop, it will be
for (int i = 0; i < lists.size() ; i++) {
int value = lists.get(i).value();
}
The other solution is to check for the type and cast it before getting the value for example
List<Object> lists = new ArrayList<>();
for (int i = 0 ; i < lists.size(); i++) {
Object object = lists.get(i);
if (object.getClass() == SubObjects.class) {
SubObjects subObject = (SubObjects) object;
int depth = subObject.depth;
}
else if if (object.getClass() == SubObjects2.class) {
SubObjects2 subObject2 = (SubObjects2) object;
int weight = subObject2.weight;
}
}
If there's no relationships between two classes other than that they both extend Object class which all objects do and you want to store objects of those two classes in the same list, you can store them in a list of objects.
Before you can access attributes of the object, you need to cast it to the type you want to use. This is how it's done before generics.
List list = new ArrayList(List.of(Integer.valueOf(1), "hello"));
for(Object o: list){
if (o instanceof Integer){
System.out.println("o is an integer.");
Integer i = (Integer) o;
System.out.println(i.intValue());
} else if (o instanceof String){
System.out.println("o is a string.");
String s = (String) o;
System.out.println(s.length());
}
}

Getting Data (long data) from One Object?

I'm working on a project and I'm being forced to make a Linked List that holds objects. Linked lists, as in a data structure that holds things like strings or int values (like arrays, vectors)
In each object there are four types of data (string, double, int, long); but I am only interested in the long value.
TL;DR:
So I guess my question is: "How do I get one value (long) from one Object that holds different types of data"?
public class A {
private int a;
private String s;
private double d;
private long l;
// have getters and setters for these
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public long getL() {
return l;
}
public void setL(long l) {
this.l = l;
}
}
now suppose u have a LinkedList as
LinkedList<A> lla = new LinkedList<A>();
and u have added object of A as
A a = new A();
//initialise the state of a
a.setA(2);
a.setS("Hello");
a.setD(4);
a.setL(5l);
add it to linkedlist
lla.add(a);
u can get object of A anytime if u have the reference of LinkedList lla as
A aObj = lla.get(position); // position is the position of object a of A
then do
long lOfA = aObj.getL();

Copy pojo fields to another pojo's setters

Let's say I have class A with public fields x and y. And let's say I have another pojo class B but that uses setters and getters, so it has setX() and setY().
I'd like to use some automatic way to copy from instance of A to B and back.
With default settings at least, Dozer's
Mapper mapper = new DozerBeanMapper();
B b = mapper.map(a, B.class);
does not copy the fields correctly.
So is there a simple configuration change that allows me to accomplish the above with Dozer, or another library that would do this for me?
I'd suggest you use:
http://modelmapper.org/
Or take a look at this question:
Copy all values from fields in one class to another through reflection
I'd say that both API's (BeanUtils) and ModelMapper provide one-liners for copy pojos' values to another pojos. Take a look # this:
http://modelmapper.org/getting-started/
Not actually a one-liner but this approach doesn't require any libs.
I was testing it using these classes:
private class A {
public int x;
public String y;
#Override
public String toString() {
return "A [x=" + x + ", y=" + y + "]";
}
}
private class B {
private int x;
private String y;
public int getX() {
return x;
}
public void setX(int x) {
System.out.println("setX");
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
System.out.println("setY");
this.y = y;
}
#Override
public String toString() {
return "B [x=" + x + ", y=" + y + "]";
}
}
To get public field we can use reflection, as for setters it's better to use bean utils:
public static <X, Y> void copyPublicFields(X donor, Y recipient) throws Exception {
for (Field field : donor.getClass().getFields()) {
for (PropertyDescriptor descriptor : Introspector.getBeanInfo(recipient.getClass()).getPropertyDescriptors()) {
if (field.getName().equals(descriptor.getName())) {
descriptor.getWriteMethod().invoke(recipient, field.get(donor));
break;
}
}
}
}
The test:
final A a = new A();
a.x = 5;
a.y = "10";
System.out.println(a);
final B b = new B();
copyPublicFields(a, b);
System.out.println(b);
And its output is:
A [x=5, y=10]
setX
setY
B [x=5, y=10]
For someone who is still looking for,
You could try this using Gson
Gson gson = new Gson();
Type type = new TypeToken<YourPOJOClass>(){}.getType();
String data = gson.toJson(workingPOJO);
coppiedPOJO = gson.fromJson(data, type);

java generic addition

I'm attempting implement the add method mentioned in the Generic sparse matrix addition question
class Matrix<T extends Number>
{
private T add(T left, T right)
{
if (left instanceof Integer)
{
return new Integer(((Integer)left).intValue() + ((Integer)right).intValue());
}
}
The compiler errors with found java.lang.Integer Required T at the line where I return a new Integer. I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number.
The compiler doesn't let you do this because T might be some other class, such as Double.
You know that T is Integer from the instanceof check, but the compiler doesn't.
Java's type system is simply not capable of expressing this. Here is a work around.
Create an interface Numeric that provides the numeric operations you are interested in, and write its implementations for the data types you are interested in.
interface Numeric<N> {
public N add(N n1, N n2);
public N subtract(N n1, N n2);
// etc.
}
class IntNumeric extends Numeric<Integer> {
public static final Numeric<Integer> INSTANCE = new IntNumeric();
private IntNumeric() {
}
public Integer add(Integer a, Integer b) {
return a + b;
}
public Integer subtract(Integer a, Integer b) {
return a - b;
}
// etc.
}
And rewrite your Matrix class constructor to accept this implementation.
class Matrix<N> {
private final Numeric<N> num;
private final List<List<N>> contents;
public Matrix(Numeric<N> num) {
this.num = num;
this.contents = /* Initialization code */;
}
public Matrix<N> add(Matrix<N> that) {
Matrix<N> out = new Matrix<N>(num);
for( ... ) {
for( ... ) {
out.contents.get(i).set(j,
num.add(
this.contents.get(i).get(j),
that.contents.get(i).get(j),
)
);
}
}
return out;
}
}
// Use site
Matrix<Integer> m = new Matrix<Integer>(IntNumeric.INSTANCE);
Hope that helps.
"I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number."
This statement is false. In general if you have:
public class B extends A {
}
public class C extends A {
}
it does not mean that B can be cast to C. So writing something like:
public <T extends A> T method(T arg) {
return (B)arg;
}
and you calling it with B b = (B)method(C); is obviously wrong.
package generics;
public class Box<T> {
public T j,k;
int l;
float f;
#SuppressWarnings("unchecked")
public void add(T j,T k) {
this.j = j;
this.k=k;
if(j.toString().contains("."))
{
this.f=Float.parseFloat(j.toString())+Float.parseFloat(k.toString());
} else{
this.l=Integer.parseInt(j.toString())+Integer.parseInt(k.toString());
}
}
public int getInt() {
return l;
}
public float getFloat() {
return f;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<Float> floatBox = new Box<Float>();
integerBox.add(new Integer(10),new Integer(20));
floatBox.add(new Float(2.2),new Float(3.3));
System.out.printf("Integer Value :%d\n\n", integerBox.getInt());
System.out.printf("float Value :%f\n", floatBox.getFloat());
}
}

Create instance from superclass instance

Consider the following case:
class A {
int x;
int y;
}
class B extends A {
int z;
}
Now, somewhere in the code this classes are used like this:
A objA = getAFromSomewhere();
B objB = null;
And in a certain situation I want to do something like
objB = objA; // can't do this
objB.z = someZ;
Of course the real objects are a bit more complicated, so it's not just about copying two ints. But they aren't overly complex either.
I know I can write a constructor for B like this:
public B(A anA) {
this.a = anA.a;
this.b = anA.b;
this.z = 0;
}
But if that's really the only way, I prefer merging the additional members of B into A.
update considering the answers
My question was not clear enough. I understand that objB = objA; can't work (thus I asked for "something like", meaning something with comparable code complexity) and I know about the issues with shallow vs deep copies.
What I was looking for is a possibility to copy the members of a base class (let's say using clone()). You may understand that copying every member manually is a bad solution as it adds complexity and redundancy to the code. Thanks for your replies anyway!
There's no trivial solution to this because there's no one-size-fits-all solution. Basically you don't have all the information within a B, so you can't guarantee you would have a "sensible" B object.
You probably just want to create a constructor in B which takes an A and copies all the A data into the new B.
If you're not scared of commons-beanutils you can use PropertyUtils
import org.apache.commons.beanutils.PropertyUtils;
class B extends A {
B(final A a) {
try {
PropertyUtils.copyProperties(this, a);
}
catch (Exception e) {
}
}
}
There is a (relatively) trivial solution!
Implement a constructor in class B that takes an instance of class A and copies the fields.
One of the reasons there's no generic solution in the language itself is because of the problem of deep copying.
For example, if the source object contains further Objects, as opposed to plain types, what would the generic copy operator do? Just copy the reference (giving a shallow copy), or make real copies?
What then if one of those objects is a Collection? Should it also copy every element of the collection, too?
The only logical conclusion would be to perform a shallow copy, but then you haven't really got a copy at all.
Perhaps you could do this:
class A {
int x;
int y;
A(A a) {
this.x = a.x;
this.y = a.y;
}
}
class B extends A {
int z;
B(A a) {
super(a);
z = 0;
}
}
You're still listing every field, but only once per class.
I am shocked too. :)
You really cannot do this: objB = objA;.
Because Renault and BMW are cars but not all cars are BMW.
Thank about A as Car, B as BMW.
Now you say:
Car car = new Renault();
BMV bmv = car; // you cannot do this. This is exactly your case.
...not because this is what people should do but more because I felt like a challenge, here is some test code which does a simple copy of the objects (using setter and getter methods):
import java.lang.reflect.Method;
import org.junit.Test;
public class ObjectUtils {
#Test
public void test() {
A a = new A();
B b = new B();
a.setX(1);
a.setY(2);
this.copyProperties(a, b);
}
private void copyProperties(Object obja, Object objb) {
Method m[] = obja.getClass().getDeclaredMethods();
for(int i=0;i<m.length;i++) {
try {
String name = m[i].getName();
if(name.startsWith("get") || name.startsWith("is")) {
Class rtype = m[i].getReturnType();
String setter = name.replaceFirst("^(get|is)","set");
Class s = objb.getClass();
Method method = s.getMethod(setter,rtype);
Object[] args = new Object[1];
args[0] = m[i].invoke(obja);
method.invoke(objb,args[0]);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
class A {
int x;
int y;
/**
* #return the x
*/
public int getX() {
return x;
}
/**
* #param x the x to set
*/
public void setX(int x) {
this.x = x;
}
/**
* #return the y
*/
public int getY() {
return y;
}
/**
* #param y the y to set
*/
public void setY(int y) {
this.y = y;
}
}
class B extends A {
int z;
/**
* #return the z
*/
public int getZ() {
return z;
}
/**
* #param z the z to set
*/
public void setZ(int z) {
this.z = z;
}
}
}
If you do not need full functionality of A, there is also an option to create class B, holding internal copy of A instance and implementing some minimal subset of methods via C interface by proxying them to instance.
class A implements IC {
int x;
int y;
public C() {
...
}
}
class B implements IC {
private A _a;
public B(A a) {
_a = a;
}
public C() {
_a.C();
}
}
Assuming that your class A has a very neat and clean setter and getter method naming convention like
setXXX(Object xxx) and corrresponding getXXX() which returns the same thing (Object xxx ) as a param passed to setXXX()
I have written a utility method using reflection
public static B createSubclassInstance(A a) throws SecurityException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Method[] aMethods = Class.forName("package.A").getDeclaredMethods();
B b = new B();
for (Method aMethod : aMethods) {
String aMethodName = aMethod.getName();
Class param = aMethod.getReturnType();
if (methodName.startsWith("get")){
String setterMethodName = methodName.replaceFirst("get", "set");
Method bMethod = Class.forName("package.B").getMethod(setterMethodName);
Object retValA = aMethod.invoke(a,null);
bMethod.invoke(b,retValA);
}
}
return b;
}
If you change your method to create B objects, you can just do what you want using:
objB = (B) objA;
objB.z = someZ;
This can even be inlined, but you need parentheses:
((B) objA).z = someZ;
If not, you have to go the long way using constructors:
objB = new B(objA);
objB.z = someZ;
In this case I would recommend to copy the fields of the superclass in the superclass. Else, if you add a field to that class later, you may forget to change the copying more easily.
class A {
int x;
int y;
public A(A objA) {
x = objA.x;
y = objA.y;
}
}
class B extends A {
int z;
public B(A objA) {
super(objA);
}
}
I prefer merging the additional members of B into A.
You can do this if your classes A and B share the same package or if the variables in your A class are declared as protected. Then you can just access the fields of the superclass.
class A {
protected int x;
protected int y;
}
class B extends A {
int z;
void merge(A a){
super.x = a.x;
y = a.y; // you do not *need* to use the super keyword, but it is a good hint to
// yourself if you read your program later and might wonder ‘where is
// that y declared?’
}
}
Useage, of course, is:
objB = new B();
objB.merge(objA);
objB.z = someZ;
I think best way is to use a factory method to create B objects from A objects.
class BFactory
{
public static B createB(A a)
{
B b = new B();
copy(a,b);
return b;
}
private static <X,Y> void copy(X src,Y dest) throws Exception
{
List<Field> aFields = getAllFields(src.getClass());
List<Field> bFields = getAllFields(dest.getClass());
for (Field aField : aFields) {
aField.setAccessible(true);
for (Field bField : bFields) {
bField.setAccessible(true);
if (aField.getName().equals(bField.getName()))
{
bField.set(dest, aField.get(src));
}
}
}
}
private static List<Field> getAllFields(Class type)
{
ArrayList<Field> allFields = new ArrayList<Field>();
while (type != Object.class)
{
Collections.addAll(allFields, type.getDeclaredFields());
type = type.getSuperclass();
}
return allFields;
}
}

Categories

Resources