safe json to java serialization/deserialization - java

I would like to know how you would do this :
I have a java data object. This object contains object attributes that contains object attributes...
I serialize my objects using json-io. But when deserializing, I want to protect the data if an object fails to deserialize. So I got the idea to json-serialize each attribute before serializing any object. This way, if an attribute fails to deserialize, the object itself is safe.
this means that if I have an object {a:v1,b:{ba:v2,bb:{bba:v3,bbb:v4}}}, I will serialize it like this instead : "{\"a\":\"v1\",\"b\":\"{\\\"ba\\\":\\\"v2\\\",\\\"bb\\\":\\\"{\\\\\\\"bba\\\\\\\":\\\\\\\"v3\\\\\\\",\\\\\\\"bbb\\\\\\\":\\\\\\\"v4\\\\\\\"}\\\"}\"}"
You see that on a very simple object it becomes very uneasy to read. Imagine with a more complex one !
I would like to do something about it, but I found no good ideas. Maybe the best would be when I read/write the json to call a function able to remove/re-add the "\" where they are needed, but I don't succeed to find the correct algorithm... Any hint ? Or maybe another method ?
Thanks a lot !

Ok. My approach was wrong. I created a Data object like a Map that contains Data or String. Then, I can safely deserialize Data elements. It means that this time I have a tree, where all the trunk is a safe Data object, and only the leafs are json-serialized generic objects.
public class Data implements Serializable {
private final Map<String, Data> node = new HashMap<>();//safe tree object
private final Map<String, String> leafs = new HashMap<>();//unsafe serialized object
}
In my previous example, the result would be :
//initial object
{a:v1,b:{ba:v2,bb:{bba:v3,bbb:v4}}}
//becomes
{"a":"{v1}","b":{"ba":"{v2}","bb":{"bba":"{v3}","bbb":"{v4}"}}}
And the \ would appear only if one of the unsafe values contains a String.
Thanks a lot Ryan, Talking to you helped me a lot to better define the problems, which is always the first step to the solution.

Related

Explicit type conversion between child spring object, and it's super java.util object

In spring I am using jdbcTemplate, but having a problem that it is returning a Linkedcaseinsensitivemap when querying for a List, when doing the following I still get the spring linkedcaseinsensitivemap, even if I cast it to java util List and define the left-side of the assignment as a java.util.List.
Firstly how is that even possible?
final java.util.List<Map<String, Object>> list = (java.util.List<Map<String, Object>>) jdbc
.queryForList("SELECT * FROM customer");
so, how would one achive doing this type of upcaste?
without needing to declare a second list allocate memory for it and then put the objects manually into the java.util.List?
Since the LinkedCaseInsensitive is subclassing the java object, Im having a hard time figuring out how to cast to the super object which is the java List. How to achieve this is a mystery at the moment.
since there is no way currently to know which brokers will use our AMQ, the goal is too strictly keep to jms objects,
So I can't start sending spring objects, since jms should be our standard, also please note I do not have the option to implement the AMQProtocol, I need to send basic java objects,
Since serialising to JSON has been suggested I will explain why it does not work in this case, why I'll need to send the Objects "as-are" to the receiver since they will put it into a Notes document.
for (int i = 1; i <= metadata.getColumnCount(); i++) {
String columnName = metadata.getColumnName(i);
Object values = sqlConnection.getRset().getObject(i);
doc.replaceItemValue(columnName, values);
}
So SO'ers, how does one achieve doing this more beautifully?
please help
thanks in advance!
A SQL select can return multiple rows, and each row has multiple selected columns.
The queryForList method you are calling returns a List with for each selected row a Map mapping column name to column value.
Map and List are interfaces, so Spring is free to pick whatever implementation it likes. It chooses the LinkedCaseInsensitiveHashMap for the Map because that map will list the keys in the order of insertion. So the order in which the columns were selected does not get lost.
If you wish to send the result list to a receiver that you know little about, you can probably best serialize it to JSON and send it as a text message.
You can serialize to JSON using a library like Gson or Jackson2. You create a serializer and feed it the object you wish to convert to a String.
So for example in Gson, where the serializer class is called Gson:
TextMessage message;
// initialize message and headers however you like
// then serialize it to String:
Gson gson = new Gson();
String json = gson.toJson(list);
// and set it in the message:
message.setText(json);
(You can also let Spring JmsTemplate do this for you using a MessageConverter that converts to JSON but I'd estimate that that's a bit harder to get working.)
Alternatively, if you wish to customize the Map that you send as an ObjectMessage, you can use a different query method that allows you to specify a custom RowMapper that creates a java.util.Map implementation of your liking. Note that if you use a TreeMap, it'll sort the columns alphabetically and if you use a HashMap, it'll put them in random order.
The receiver then can unpack the JSON back into Java objects. gson.fromGson(json) will return a List of Maps.
This is the only way I've figured out how to have a child object to become it's parent class without breaking out into methods - in my described scenario doing the following:
final java.util.ArrayList<java.util.Map<String, Object>> javaList = new java.util.ArrayList<java.util.Map<String, Object>>();
final java.util.List<java.util.Map<String, Object>> list = jdbc
.queryForList("SELECT * FROM customer");
javaList.addAll(list);
But doesn't look good to me, how would one achive this in a more right way?

How do I access the data in Java objects returned by User.getAddresses() and User.getPhones()?

In com.google.api.services.admin.directory.model.User, many methods, such as getAddresses() and getPhones(), return a Java object that I can’t figure out what to do with.
Using toString(), I can see that the data I want is in the object (and looks like a list of HashMaps), but I can’t figure out how to convert it to a form that I can access, such as a list or array of UserAddress or UserPhone?
I’d also like to know how to build such objects so I can update users (although I suppose it’s likely that the answer to the first part of my question may make how to build them obvious)?
I have been able to update others things that don’t involve such objects, so I don’t need help with reading and updating in general, but I’ve struggling with these object for a couple of days now and can’t figure it out. Thanks.
The Google Directoy API uses JSON for communication. The Java client library used to communicate with the API parses and serializes the JSON to and from Java objects for easier usage in code. Have a look here for an idea of how it works: https://code.google.com/p/google-http-java-client/wiki/JSON
The problem with the current version of the library is that it doesn't serialize all the fields in the User class to usable objects. Instead maps, or list of maps, are used for complex fields. For example the phones field should be turned into a list of UserPhone objects, but instead becomes a list of maps. The only field that is being properly serialized is the name field, being a UserName object.
One way to manually turn the maps into the correct object is to use a json parser like Gson and parse the maps. Like this:
Gson gson = new GsonBuilder().create();
ArrayList phones = (ArrayList) user.getPhones();
for (Object phone : phones) {
UserPhone userPhone = gson.fromJson(phone.toString(), UserPhone.class);
System.out.println(userPhone.getType() + "=" + userPhone.getValue());
}
I believe those methods return a collection, in which case you'll probably want to access the items they contain via their iterator. Something like this should work:
ListIterator addresses = user.getAddresses().iterator();
while(addresses.hasNext()) {
Address address = addresses.next();
// do something with the address
}
If you're not familiar with the Iterator object, this article might help: How to use Iterator
Thank you, but User.getAddresses() and User.getPhones() do not have iterator methods, so neither of the answers proposed here will work.
"ListIterator addresses = user.getAddresses().iterator();" gets the compiler error “The method iterator() is undefined for the type Object”.
"for (UserAddress addr : user.getAddresses())" gets the compiler error “Can only iterate over an array or an instance of java.lang.Iterable”.
I finally found a way to get the job done, though. The follow codes actually works, even though it's difficult to believe this is the way I'm "supposed to" do it.
ArrayList<ArrayMap<String,String>> phones = (ArrayList<ArrayMap<String,String>>)user.getPhones();
for (ArrayMap<String,String> phone : phones)
System.out.println(phone.get("type") + "=" + phone.get("value"));
It’d be nice to get the data into an instance of UserPhone, but I can’t figure out how to do that (other than doing a get & UserPhone.setXxxx for every possible keyword).
I was able to update a phone number by passing User.setPhones() an ArrayList<UserPhone> that I built from scratch.

Jackson - Working with arrays of objects, appending and removing

I'm working with the Jackson API in Java for dealing with JSON. I've been working with it a bit here and there, but nothing too in-depth.
Currently, I'm looking for a good way to take an array of JSON objects (either via a stream or String) that was created from a list of POJOs and append or remove a POJO. In the case of appending, duplicate checking isn't really necessary. As a simple example, let's say I have this array built from a list of Java objects with a single variable named "field":
[{"field":"value"},{"field":"value2"}]
And I'd like to append an object of the same type with "field" set to "value3". I could simply deserialize the whole array into a List of Java Objects, add the new object, then serialize it back into JSON, but that feels like overkill. It would be better if I could use Jackson to simply serialize the new object and append it to the end of the JSON array. The same would apply to removing an existing object from the array.
I've found a way, but strangely, it's over twice as slow as the direct deserialize-add-reserialze method with a list of 500 POJOs that have three fields each, and it only gets worse with more objects.
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getJsonFactory().createJsonParser(input);
JsonGenerator gen = mapper.getJsonFactory().createJsonGenerator(output, JsonEncoding.UTF8);
gen.writeStartArray();
parser.nextToken();
while (parser.nextToken() == JsonToken.START_OBJECT) {
//gen.writeTree(parser.readValueAsTree());
//parser.skipChildren();
//EDIT: This is much faster as the only method in the loop:
gen.copyCurrentStructure(parser);
}
gen.writeTree(mapper.valueToTree(/*new Object to add*/);
gen.writeEndArray();
gen.close();
parser.close();
Even if I don't get each object as a tree and instead move them iteratively as fields/values, it's a bit faster, but still considerably slower than the alternative. Is this to be expected or is there a better way to handle it as streaming data rather than the bulk JSON-to-Java-to-JSON method?
EDIT: AHA! Found that the JsonGenerator can directly copy the current structure from a JsonParser withcopyCurrentStructure(JsonParser). Using this in the while loop is faster and now outruns the bruteforce method by a considerable amount.

Java Use string as object call

Good Afternoon,
i would like to ask regarding the methods to use string as reference.
Let say, that i got two object of type LinkedList named ChinaShip and HongkongShip
Normally, if i wanted to access a method (for example getFirst())
i will type ChinaShip.getFirst()
Now, let say that in other object, i got a variable Destination which content is a String.
The example of the Content will be China and Hongkong
Is it possible to use the content of the variable as the name for accessing the LinkedList object?
my approach first would be concatenate the variable first, which will be Destination + "Ship"
This will produce a string which is ChinaShip and HongkongShip
The reason i'm doing this way rather than comparing the string is that the Destination consist of hundreds of posibilities.
Thank You Very Much.
Regards,
Unfortunately you can't do that in Java. But this is closer with that:
HashMap<String, LinkedList> dest = new HashMap<String, LinkedList>();
dest.put("China", ChinaShip);
dest.put("Hongkong", HongkongShip);
.....
if(dest.containsKey(Destination){
dest.get(Destination).getFirst();
}
You can use the reflection API. If the lists are declared in the class MyClass you can use the following code:
LinkedList list = (LinkedList) MyClass.class.getDeclaredField(Destination + "Ship").get(this);
This assumes that the above code is called from within a MyClass object, otherwise the get(this) call must be changed to get(myClassInstance). Though as MadProgrammer mentions, you might be better of using a Map.
You can use a Map and use the desitnation string as your key because these will be unique:
Map<Desitnation, value> destinations = new HashMap<Desitnation, value>();
then search through the Map for your destination key:
http://www.tutorialspoint.com/java/util/hashmap_get.htm
I think you need to re-work your architecture. You shouldn't have to create method names from Strings.
It seems to me like you need a Ship object which has a destination, and a linkedlist of Ships.
If you need to map ships by destination, what you can also do is have a Map where they key is the destination string, and the value is the linked list of ships going to that destination.
So if you do a map.get("China") you will get a list of ships going to China, and from there you can do what you want.

Help need with transforming Java lists/collections or something

I have a list of objects returned from getJdbcTemplate().query
that look like this
object(test,test,test,1)
object(test,test,test,2)
object(test,test,test,3)
How can I transpose these into one object that looks like this
object(test,test,test,list<t>({1,2,3}))
Hopefuly you get the idea from my ropey psuedo object representation :)
I think using RowMapper can be a little painful. Perhaps, you can do something like this (by the way, this is my pseudo):-
List<Map> rows = getJdbcTemplate().queryForList(sql);
MyObject obj = null;
for (Map row : rows) {
// configure the first 3 fields upon object creation.
if (obj == null) {
obj = new MyObject(row.get("firstField"), row.get("secondField"), row.get("thirdField"));
}
// basically add each item into the list
obj.addToList(row.get("fourthField"));
}
JdbcTemplate deals with rows, so you need a RowMapper to extract the values and convert them into a List of a custom type (implement a class that corresponds to this structure object(test,test,test,1)). Then you can work on the extracted values and assemble your new object from the list values.
Reference:
Examples of JdbcTemplate class
usage
JdbcTemplate javadoc
RowMapper<T> javadoc
Couldn't you use a 2 dimensional array?
http://www.willamette.edu/~gorr/classes/cs231/lectures/chapter9/arrays2d.htm
I'm kind of a noob at java so if I'm not correct, please excuse my ignorance.
Extend your Object Model.
You need to create a new object, similar to the one you are creating with the individual value argument, which instead takes a list or a collection as the final argument. Instead of storing a single value there, your object will store a list or a collection there. If this list or collection will be immutable once the object has been created, you should consider converting the data to an int[] before storing it.
Then, build whatever methods you need on this new object. You can even write a method to return an array of the old objects, where each object has only one value in it.

Categories