How to use Wobly serializer on Android - java

I'm looking for the alternatives to serialize objects in my Android project. I found Wobly which seem to be fast and small. I understand how to create Wobly wrappers using WoblyImpl but I'm totally confused with how to write/read these objects from the file system? When to run WoblyGenerator and can it be done within my code? Can someone post a code example?

Wobly doesn't support unknown Object fields. So fields like:
Object a;
List<Object> b;
Map<Integer, Object> c;
cannot be serialized with Wobly.
It supports all primitive classes (and their boxed counterparts), all Wobly classes, any Array/List/Map combination of the above.
So in your case, problem is that JSONArray implements List<Object>. If you know what kind of object JSONArray holds, for example List<Map<Integer, String>>, you can write:
class Example extends WoblyImpl {
#WoblyField(id = 0)
List<Map<Integer, String>> array;
public void setArray(JSONArray json) {
array = (List)json;
}
}
Though after deserialization you will get ArrayList<HashMap<Integer,String>> and not JSONArray back.
If you don't know what object JSONArray is holding, it would be painful to make it work with Wobly, if at all possible. You can check out comprehensive comparison of serialization libraries here:
https://github.com/eishay/jvm-serializers/wiki

OK, I got it. If you wondered here and want to know how to do it here are the steps:
Create your class by extending WoblyImpl and annotate the fields according to the instructions
Then run WoblyGenerator.updateSourceFolder("c:/foo/src"); where the parameter is directory containing your file (or package). I created a small project in Eclipse for that but you can also run this from the command line using supplied wobly-generator.jar
This step will inject serialization code into your source file which will include read and write methods
Gotcha: this didn't work for smart-json JSONObject or JSONArray or for HashMap. The error I got is this:
java.lang.IllegalArgumentException: next type for class net.minidev.json.JSONObject of index 0, class java.lang.Class
at com.wowd.wobly.generation.WoblyGeneratorUtils.extractNextType(WoblyGeneratorUtils.java:91)
at com.wowd.wobly.generation.types.impl.MapTypeCodeGenerator.defaultTypeFormat(MapTypeCodeGenerator.java:163)
at com.wowd.wobly.generation.types.TypeCodeHandler.defaultTypeFormat(TypeCodeHandler.java:121)
at com.wowd.wobly.generation.WoblyGeneratorUtils.adjusFormatForCompressed(WoblyGeneratorUtils.java:317)
at com.wowd.wobly.generation.WoblyCodeGenerator.generateWriteFieldCode(WoblyCodeGenerator.java:178)
at com.wowd.wobly.generation.WoblyCodeGenerator.generateWriteMethod(WoblyCodeGenerator.java:270)
at com.wowd.wobly.generation.WoblyCodeGenerator.generateFieldsAndMethods(WoblyCodeGenerator.java:647)
at com.wowd.wobly.generation.WoblyCodeGenerator.generateRegularCode(WoblyCodeGenerator.java:721)
at com.wowd.wobly.generation.WoblyCodeGenerator.generateCode(WoblyCodeGenerator.java:677)
at com.wowd.wobly.updater.GenerateAndReplace.update(GenerateAndReplace.java:130)
at com.wowd.wobly.updater.GenerateAndReplace$1.execute(GenerateAndReplace.java:198)
at com.wowd.wobly.updater.GenerateAndReplace$1.execute(GenerateAndReplace.java:1)
at com.wowd.common.functions.impl.FilterProcedure.execute(FilterProcedure.java:40)
at com.wowd.wobly.updater.SourceFilesVisitor.visitDir(SourceFilesVisitor.java:69)
at com.wowd.wobly.updater.SourceFilesVisitor.visitDir(SourceFilesVisitor.java:60)
at com.wowd.wobly.updater.SourceFilesVisitor.visitDir(SourceFilesVisitor.java:60)
at com.wowd.wobly.updater.SourceFilesVisitor.visitDir(SourceFilesVisitor.java:60)
at com.wowd.wobly.updater.SourceFilesVisitor.visitPackage(SourceFilesVisitor.java:38)
at com.wowd.wobly.updater.GenerateAndReplace.updateInPackage(GenerateAndReplace.java:190) WoblyParcel error
at com.wowd.wobly.WoblyGenerator.updatePackage(WoblyGenerator.java:60)
at com.wowd.wobly.WoblyGenerator.updateSourceFolder(WoblyGenerator.java:49)
at Generator.main(Generator.java:19)
If someone can tell me how to fix that - post it as a separate answer and I'll accept it

Related

Using scala.collection.immutable.Map inside my java class

I get bellow exception from my java codes.
java.lang.ClassCastException: scala.collection.immutable.Map$Map1 cannot be cast to java.util.HashMap
at au.com.vroc.udf.medianUDF.update(medianUDF.java:79)
I am getting error in my spark application when I cast the buffer to HashMap of java.utill. This is my codes:
public void update(MutableAggregationBuffer buffer, Row input) {
if (!input.isNullAt(0)) {
HashMap currentBuffer=(HashMap) buffer.get(0);//getting exception here
//HashMap currentBuffer=new HashMap();
currentBuffer.put(input.getLong(0), input.getDouble(0));
//currentBuffer.add(currentMap);
buffer.update(0, currentBuffer);
}
}
I guess instead of java hashmap I have to use "scala.collection.immutable.Map$Map1" inside my java class. Can I use any tool in "JavaConversions" namespace.
Anyhep would be appreciated!
Simplest approach would likely be to use Scala Converters.
It should look something like this (not tested, but type-checks):
import scala.collections.JavaConverters
java.util.Map currentBuffer = JavaConverters.mapAsJavaMapConverter(buffer.get(0)).asJava();
Please note that it returns type-parameterized map (i.e. java.util.Map<K, V>), not the non-parameterized java.util.HashMapin your example - you might want to alter the rest of your code to work on the parameterized maps for better type safety.
You get java.util.Map you should use getJavaMap method:
java.util.Map<T, U> currentBuffer = (java.util.Map<T, U>) first.getJavaMap(0)
Note that this is not HashMap - initialized value is Encoded on update and decoded on get. To modify it, you have to make a copy.

Is there some way for a Jackson Delegate-based Creator to access the raw Json String?

Is there some way for a Jackson Delegate-based creator to access the raw Json String?
#JsonCreator
private static MyClass createFromJson(Map<String, Object> jsonProperties) {
return new MyClass(rawJson);
}
I am able to get the raw input as a Map of Strings to Objects in the code above, but I want to be able to access the json as a string. I tried the code below (based off of http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html) but that code as written is never invoked.
#JsonCreator
private static MyClass createFromJson(String rawJson) {
return new MyClass(rawJson);
}
Note: This is a spring boot application (1.3.1.RELEASE) that uses Jackson 2.6.4.
Looks like this type of functionality would not make sense in this context. In fact, it appears to me now that requesting the JSON string in this instance defeats the purpose of using jackson in the first place. However if anyone finds themselves here, then the comments from Sotirios Delimanolis may be useful:
"Hack: you can receive a JsonNode as the parameter type and use its toString method to get the corresponding JSON."
"It looks like you want a JsonDeserializer"

Instantiate generic based on property file setting

I'm building a data driven test system. I have done this before in XML but json is giving me some interesting issues.
For each request and response type json, I have a setting in my script where I specify a pojo type. This type is instantiated to a class object thats passed to jackson to marshal the json into a usable pojo. so its like this:
"responseType": "java.util.List",
eventually gets pumped to
Class<?> reponseType = null;
try {
if (d.shouldPass) {
reponseType = Class.forName(d.responseType);
}
} catch (ClassNotFoundException e) {
throw new RequestResponseTypeInvalid(testName);
}
and I have usable class info to use in jackson. My problem is I need to do this:
"responseType": "java.util.List<foo>",
otherwise complex json types parse as hashmaps instead of pojo's. I suppose I can get creative and put something in to go from hashmap to pojo if I need to but I was wondering if there was any straight forward way to do this.
I suppose another way is to implement a factory class where I could say list_foo in the property file and have the factory class map that to an actual class object. That wouldn't be very hard but not as easy as just using the property.
thanks
You can't do this in the way that you're hoping, I'm afraid. Generics are a compile-time thing only, and can't be used in this way at runtime, because of type erasure.
The best you could do would be to have some list_foo properties, and map these explicitly to List<Foo> and so in in your code. But you can't do it by reflection.

Android - JSON stored list contains objects that revert to superclass when app is exited, reopened

I have an ArrayList <GeneralTemplate> items
Throughout my program, I am adding Routines which are subclasses of GeneralTemplate i.e items.add(new Routine("Test")); and all is well.
Most importantly, I can do the following.. Routine myRoutine = items.get(position);
I am saving this big list of items in a special data object in JSON using Google's GSON library. I believe this may be the problem.
This data object contains the ArrayList <GeneralTemplate> items. During my program, I can see that the routines stored in the items list are indeed Routine objects. I then save it using the code below. I have followed this process with the debugger and when I setRoutineList, the Routine objects are maintained without problem.
// Global save String method
public static void save()
{
Editor editor = sharedPreferences.edit();
RoutineData tempSaveObject = new RoutineData();
tempSaveObject.setRoutineList(routineList);
String routineListInJSON = gson.toJson(tempSaveObject);
editor.putString(ROUTINE_LIST, routineListInJSON).commit();
}
The problem occurs when I restart the app and retreive the data. All of the items in the list revert to GeneralTemplate objects and cannot be cast back to Routine via Routine routine = (Routine) items.get(position) -> ClassCastException (Code for loading below)
// Get a global sharedPreferences object that can be used amongst Activities
sharedPreferences = this.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
if (sharedPreferences.contains(ROUTINE_LIST))
{
String routineListJSON = sharedPreferences.getString(ROUTINE_LIST, null);
routineDataObject = gson.fromJson(routineListJSON, RoutineData.class);
routineList = routineDataObject.getRoutineList();
}
else
{
routineList = new ArrayList<GeneralTemplate>();
}
Therefore, I can't access specific methods and variables because I cant regain the subclass context. There are several other instances of this problem, so if there is any good solution to this that you good folks knowledge, it would help a lot.
Thanks!
SORTED:
Genson JSON library.
https://code.google.com/p/genson/downloads/detail?name=genson-0.94.jar&can=2&q=
Made things so much easier, no need for custom serializers/deserializers. Took care of all the in depth polymorphism stuff by default.
Implemented as shown in Eugen's answer
This is due to the fact that you have a list of GeneralTemplate, while serializing Gson knows the concrete type of each element in the list but during deserialization Gson doesn't know into which type to deserialize (as it is a list of GeneralTemplate).
I am not sure but it looks like they have some contrib (not part of Gson) that allows to add type information in the serialized stream, this allows Gson to deserialize back into the right type.
You could also try out Genson library, handling polymorphic types is supported out of the box. It has the features provided by Gson and some others too. Here is how you can achieve it:
// first configure your Genson instance to enable polymorphic types support and
// serialization based on concrete types
Genson genson = new Genson.Builder()
.setWithClassMetadata(true)
.setUseRuntimeTypeForSerialization(true)
.create();
// and now just use it to serialize/deser
String json = genson.serialize(routineData);
RoutineData data = genson.deserialize(json, RoutineData.class);
EDIT
Problem solved. The Routine class had no default constructor. Putting #JsonProperty("name") on the ctr parameter and using gensons previous configuration solved the problem.

how to automatically copy values from java bean to protobuf message object using java reflection?

Typically I could copy values between two java beans, which have identical property names, using BeanUtils with java reflection e.g. PropertyUtils.setProperty(....)
In protobuf Message, we use the message builder class to set the value. This works but I would rather use reflection to automatically copy properties from the bean to the message as both have identical property names and type.
When I invoke the PropertyUtils.setProperty on the builder object ( got from message.newBuilder()), I get this message.
java.lang.NoSuchMethodException: Property 'testProp' has no setter method in class 'class teststuff.TestBeanProtos$TestBeanMessage$Builder'
How do I automatically copy values from java bean to protobuf message object (and vice-versa) using java reflection?
I hate to answer my question but I cant believe that I am the only one who ran into this problem. Documenting solution here in case other people are also getting started with protobuf and java. Using reflection saves wrting dozens of getter and setters.
Ok , I managed to get it to work using some of example test code shipping with protobuf. This is a very simple use case; typically a message would be a lot more complex. This code does not handle nested messages or repeated messages.
public static void setMessageBuilder(com.google.protobuf.GeneratedMessage.Builder message,Descriptors.Descriptor descriptor,Object srcObject) throws Exception {
String cname = srcObject.getClass().getName();
/*BeanMapper.getSimpleProperties -- this is a warpper method that gets the list of property names*/
List<String> simpleProps = BeanMapper.getSimpleProperties(srcObject.getClass());
Map map = new HashMap();
for (String pName : simpleProps) {
System.out.println(" processing property "+ pName);
Object value= PropertyUtils.getProperty(srcObject, pName);
if(value==null) continue;
Descriptors.FieldDescriptor fd=descriptor.findFieldByName(pName) ;
System.out.println(" property "+ pName+" , found fd :"+ (fd==null ? "nul":"ok"));
message.setField(fd, value);
System.out.println(" property "+ pName+" set ok,");
}
return ;
}
I may be off, but would protostuff help? It has nice extended support for working with other data formats, types. And even if it didn't have direct conversion support, if you go to/from JSON there are many choices for good data binding.
You can go throw all properties getClass().getFields() and make copy using reflection. It will be smt like:
for(Field f : to.getClass().getFields()){
f.set(to, from.getClass().getField(f.getName()).get(from));
}
+ probably you might be use field.setAccessible(true) invocation.
I don't know the size of your project but you may want to try Dozer, a mapper that recursively copies data from one object to another of the same type or between different complex types. Supports implicit and explicit mapping as well. I used it in a big project and worked very well. It could be as simple as
Mapper mapper = new DozerBeanMapper();
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
I've got the same issue, the solution is a little bit tricky.
Please use
MethodUtils.invokeMethod
instead.
where the method name is "setXXX".

Categories