Read JsonNode into a pre-existed POJO - java

currently I'm doing this to convert JsonNode to a POJO:
try {
MyClass obj = mapper.treeToValue(jsonData, MyClass.class)));
/* consume obj */
} catch (JsonProcessingException ex) {
return false;
}
But sometimes I don't want to get a new instance of MyClass. I have have populated it before and now I just want to set new values for some fields and keep old values for unchanged fields. What I want is something like this: mapper.readJsonNodeToPOJO(jsonData, obj))); Is it possible to do this?

Use the ObjectMapper.readerForUpdating method. Similar question has been asked here and here

You can do an inner custom object:
public class MyClass{
MyNode node:
....
}
public class MyNode{
.....
}
This way you can do:
MyClass obj = mapper.treeToValue(jsonData, MyClass.class)));
and:
obj.setNode(mapper.treeToValue(jsonSubData, MyNode.class))

Related

org.mapdb.DBException$SerializationError when storing JSONArray in MapDB using ELSA Serialization

I have a class that store a Long value and JSONArray.
Class SomeClass {
private Long longValue;
private JSONArray jsonArray;
//Default and parameterised constructors.
//Getters and Setters.
}
I'm storing these values in a NavigableMap<?, SomeClass>. ? - String / Long. I get a treeMap from MapDB as follows:
private DB mapDB = MapDBUtil.getMapDB(); //Opening or creating and getting MapDB DB object
NavigableMap<Long,SomeClass> treeMap = mapDB.treeMap(treeName).keySerializer(Serializer.LONG).valueSerializer(Serializer.ELSA).createOrOpen();
When I try to add some value to the map obtained, say:
SomeClass instance = new SomeClass("Hello", jsonArray);
treeMap.put("test", instance);
I get org.mapdb.DBException$SerializationError. I figured the issue is due to serializing JSONArray. I want to either implement a custom serializer or use some other way to serialize and store this data. I tried implementing Serializable and also ElsaSerializer in 'SomeClass' but both of those don't seem to work. I have also tried to use Serializer.JAVA when Serializable interface is implemented but that doesn't work too. I'm not sure about what I'm doing wrong. Any help would be really appreciated.
I ended up fixing it by implementing a custom serializer and using it as follows:
Class SomeClassSerialzer extends GroupSerializerObjectArray<SomeClass> {
#Override
public void serialize(DataOutput2 dataOutput2, SomeClass someClass) throws IOException {
dataOutput2.writeLong(someClass.getLong());
dataOutput2.writeUTF(threatSourceData.getJSONArray().toString());
}
#Override
public SomeClass deserialize(DataInput2 dataInput2, int i) throws IOException {
JSONArray jsonArray = null;
Long longValue = dataInput2.readLong();
try {
categories = new JSONArray(dataInput2.readUTF());
} catch (JSONException ignored) {
}
return new SomeClass(reputation, categories);
}
}
When getting BTreeMap from MapDB, use the SomeClassSerialzer as follows:
NavigableMap<Long,SomeClass> treeMap = mapDB.treeMap(treeName).keySerializer(Serializer.LONG).valueSerializer(new SomeClassSerialzer()).createOrOpen();

Deserialize json by class name

How i can deserialize my object from json string, if i have only string name of my class, by canonical name invoke, and json string representation of object?
In other words, i need method like this:
public <T> T deserialize(String json, String className) {
// some code
}
We have class name and json string - and we need to deserialize json to java object.
I know how to deserialize json to object if i know the class of object, for example, we can use Jackson:
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);
But in my task there is a different classes - it may be Cat.class, Dog.class, Car.class and etc. And every class with different state. And i need universal method for deserializing.
I write something like:
public final class Utils implements Serializable {
private Utils () {
throw new AssertionError();
}
private static ObjectMapper objectMapper = new ObjectMapper();
public static String toJson(Object obj) {
String objectToJson;
try {
objectToJson = objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(String.format("Can't serialize object %s to JSON string", obj), e);
}
return objectToJson;
}
public static <T> T fromJson(String json, String className) throws ClassNotFoundException, IOException {
Class<?> clz = Class.forName(className);
return (T) objectMapper.readValue(json, clz);
}
}
And it works with example of car above, but with a warning cast exception.
But maybe there is a better way?
Oh, and not all objects will be so simple. Some of them would encapsulate collections and other objects.
The problem stems from the compiler wanting to (virtually) make a different instance of this method for every type T that it is used on. However, there is nothing in the arguments to hang its hat on.
If the caller doesn't know what class to expect, other than a String representation of that class (which I'm assuming has been saved in the JSON as well?), what is he going to do with the result of this call? Since he doesn't know, he must be using it as simply Object, in which case the method might as well simply return Object.
If the caller does know the class, then he can pass in a Class as the argument, and you won't have any issues.
It occurred to me as writing this that ObectMapper must have a similar problem for some of its readValue methods, such as the one that accepts ResolvedType instead of Class. I notice that, in that class' source code, it includes /unchecked/ before the class. I"m not sure if that is to get around this issue or not, but it makes sense.

To create a copy of object in java w/o clone,copy constructor and copy factory

guys although this may sound like a question which is already being asked but its not.
The issue here is simple, i want to create an exact copy of an object without using clone,copy constructor and copy factory methods, because we can't make the changes to the classes(No Rights).
assume i have a Dog object
i want to create one more Dog object and in this duplicate i have to change the values of some attributes but the original object should not get affected in any way
Thanks
You can consider serialization/deserialization if the object supports that, but it might be heavy performance-wise.
Using ObjectOutputStream is also another option: http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html#replaceObject%28java.lang.Object%29
Also look at "Item 76: Write readObject methods defensively" of "Effective Java". It shows some nasty tricks you can play with object input streams.
You can just create a new object for NewDog using OldDog
Have you considered something like this?
NewDog dog = new NewDog(someOldDogObject);
While constructor of NewDog can be.
public NewDog(OldDog oldDog){
this.dogWeight = oldDog.dogWeight; // keeping the same weight
this.dogName = "newDog" + oldDog.dogName; // changing your dog name as per rquirement.
}
1) Using Apache Beanutils
Object cloned = BeanUtils.cloneBean(obj);//pass object for cloning
2) using reflection
public <T> T clone(T obj1) {
try {
Class clazz = obj1.getClass();
T obj2 = (T) clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
int modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
field.set(obj2, field.get(obj1));
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
return null;
}
}
return obj2;
} catch (InstantiationException | IllegalAccessException ex) {
return null;
}
}
You can create an util method that will do this for you, just like this
public class MyDogUtils {
public Dog copy(final Dog res, final Dog dest) {
final Dog ret = (dest == null) ? new Dog() : dest;
ret.setName(res.getName());
// some code here
return ret;
}
}
You can use a helper class/method:
MyObject cloneMyObject(MyObject o) {
MyObject cloned = new MyObject();
cloned.fieldOne = o.fieldOne;
cloned.fieldTwo = o.fieldTwo;
// Or this depending on how MyObject was implemented
// cloned.setFieldOne(o.getFieldOne());
// cloned.setFieldTwo(o.getFieldTwo());
return cloned;
}
As a side note, to get a deep cloned object make sure all the reference types are cloned before they are added to the new object.

Gson serialize POJO with root value included?

I'm having a problem serializing an object using Gson.
#XmlRootElement
class Foo implements Serializable {
private int number;
private String str;
public Foo() {
number = 10;
str = "hello";
}
}
Gson will serialize this into a JSON
{"number":10,"str":"hello"}.
However, I want it to be
{"Foo":{"number":10,"str":"hello"}},
so basically including the top level element. I tried to google a way to do this in Gson, but no luck. Anyone knows if there is a way to achieve this?
Thanks!
You need to add the element at the top of the the object tree. Something like this:
Gson gson = new Gson();
JsonElement je = gson.toJsonTree(new Foo());
JsonObject jo = new JsonObject();
jo.add("Foo", je);
System.out.println(jo.toString());
// Prints {"Foo":{"number":10,"str":"hello"}}
Instead of hardcoding the type you can do:
...
jo.add(Foo.getClass().getSimpleName(), je);
A better way to do this is to create a wrapper class and then create an object of Foo inside it.
Sample code:
public class ResponseWrapper {
#SerializedName("Foo")
private Foo foo;
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo= foo;
}
}
Then you can easily parse to JSON using:
new GsonBuilder().create().toJson(responseWrapperObj);
which will give you the desired structure:
{"Foo":{"number":10,"str":"hello"}}
If you are using Jackson api use the below lines
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);

BeanUtils.copyProperties ignoring null values

I have the following class:
import org.apache.commons.beanutils.BeanUtils;
import com.thoughtworks.xstream.XStream;
...
public class MyBean {
protected static final XStream XSTREAM = new XStream(new DomDriver());
protected String name;
protected Something something;
public MyBean() {
something = new Something();
}
public MyBean(String xml) {
this();
MyBean beanFromXML = (MyBean) XSTREAM.fromXML(new StringReader(xml));
BeanUtils.copyProperties(this, beanFromXML);
}
public String toString() {
return XSTREAM.toXML(this);
}
// Getters and setters...
}
It's a bean with ability to serialize and deserialize to/from XML using XStream.
I also added a non-args constructor that initializes something, to avoid null pointer errors - the bean is actually a lot more complex, and I don't want to be checking "is something != null?" a million times.
The problem arises when I use the XML-constructor. Lets say I've the following XML:
<myBean>
<name>John</name>
</myBean>
This is what I would like the constructor to do:
name: "John";
something: new Something();
However, since there is no <something> element in the XML, BeanUtils.copyProperties makes something = null;, thus what I get is:
name: "John"
something: null
How can I copy beanFromXML's properties into this... but ignoring the null properties instead of overwriting them?
You can create a custom converter that creates a default value for null properties:
public class MyNullConverter implements Converter {
#Override
public Object convert(final Class type, final Object value) {
try {
return value == null ? type.newInstance() : value;
} catch (final InstantiationException e) {
return null;
} catch (final IllegalAccessException e) {
return null;
}
}
}
Then register it for bean classes you want default (empty) values:
ConvertUtils.register(new MyNullConverter(), Something.class);
Your code will now work. The only thing that might bug you, is that your Something gets initialized twice. Don't know if this is OK...
BTW, if you want a more fine grained control over the process: use BeanUtilsBean, PropertyUtilsBean, and ConvertUtilsBean instead.
You have xstream alias methods to map a property name to class.
Following link will be much more helpful
http://x-stream.github.io/alias-tutorial.html

Categories

Resources