Serializing and deserializing in android application - java

I am writing an Android app for a co-worker that keeps track of Kids signed up for a soccer league. I am currently having trouble saving/serializing my roster then deserializing it later. The object I am serializing is an array of Player objects. The custom player class implements serializable so an array of them should be fine to serialize (as far as I know).
My serialization/saving method:
String ser = SerializeObject.objectToString(currentRoster.getRosterArray());
if (ser != null && !ser.equalsIgnoreCase("")) {
SerializeObject.WriteSettings(this, ser, "playerRoster"); //.dat extension
} else {
System.out.println("Object not saved");
SerializeObject.WriteSettings(this, "", "playerRoster");
}
My deserialization method:
String ser = SerializeObject.ReadSettings(this, "playerRoster");
if (ser != null && !ser.equalsIgnoreCase("")) {
Object obj = SerializeObject.stringToObject(ser);
// Then cast it to your object and
if (obj instanceof Player[]) {
// Do something
loadedRoster = (Player[]) obj;
System.out.println(loadedRoster[0]);
}
}
The result I am getting in my app is jargon for every player in the array when deserialized.
My question is on if I am correctly saving and loading the data, or am I forgetting something. (I left out some of the filler code and exception handling to keep it cleaner)
Thanks for any help!

When facing the problem of (de)serialization or (un)marshalling, I turned to JAXB to (de)serialize json or xml. I tried Jackson, but didn't get the results I was looking for, particularly with my xml. Jackson likes to set namespaces for XML (and defaults to "") and I needed mine without. Other than that, it was great, no dependencies and it'll handle well formed XML and JSON unlike gson and JSON-java.
When reading about using any of the above approaches you can't go wrong reading anything by Blaise Doughan or StaxMan. You can find a tutorial about JAXB in general right here. For using MOXy as your JAXB provider, this shows all the necessary code and links to anything else you need to know to (de)serialize/(un)marshal your objects.

Related

Flatbuffers: how do you build nested tables?

I have a 3-level nested Java POJO that looks like this in the schema file:
struct FPathSegment {
originIata:ushort;
destinationIata:ushort;
}
table FPathConnection {
segments:[FPathSegment];
}
table FPath {
connections:[FPathConnection];
}
When I try to serialize a Java POJO to the Flatbuffer equivalent I pretty much get "nested serialzation is not allowed" error every time I try to use a common FlatBufferBuilder to build this entire object graph.
There is no clue in the docs to state if I have a single builder for the entire graph? A separate one for every table/struct? If separate, how do you import the child objects into the parent?
There are all these methods like create/start/add various vectors, but no explanation what builders go in there. Painfully complicated.
Here is my Java code where I attempt to serialize my Java POJO into Flatbuffers equivalent:
private FPath convert(Path path) {
FlatBufferBuilder bld = new FlatBufferBuilder(1024);
// build the Flatbuffer object
FPath.startFPath(bld);
FPath.startConnectionsVector(bld, path.getConnections().size());
for(Path.PathConnection connection : path.getConnections()) {
FPathConnection.startFPathConnection(bld);
for(Path.PathSegment segment : connection.getSegments()) {
FPathSegment.createFPathSegment(bld,
stringCache.getPointer(segment.getOriginIata()),
stringCache.getPointer(segment.getDestinationIata()));
}
FPathConnection.endFPathConnection(bld);
}
FPath.endFPath(bld);
return FPath.getRootAsFPath(bld.dataBuffer());
}
Every start() method throws a "FlatBuffers: object serialization must not be nested" exception, can't figure out what is the way to do this.
You use a single FlatBufferBuilder, but you must finish serializing children before starting the parents.
In your case, that requires you to move FPath.startFPath to the end, and FPath.startConnectionsVector to just before that. This means you need to store the offsets for each FPathConnection in a temp array.
This will make the nesting error go away.
The reason for this inconvenience is to allow the serialization process to proceed without any temporary data structures.

Handling inconsistent data types in REST results (json) in Java

I'm new, and attempting to work with the Rest API on setlist.fm from Android Studio, but am having some issues when fitting my GET request results into my Java data model.
Particularly, I have modeled "sets" ("set" refers to a set played at a concert) as a Java class. But commonly, I get results back from my HTTP requests that have "set" as an empty string or even an array.
I'll use this following GET request for all Radiohead setlists as an example:
http://api.setlist.fm/rest/0.1/artist/a74b1b7f-71a5-4011-9441-d0b5e4122711/setlists.json
Notice how, for the most part, "sets" is an object. But in some instances, it is a String. In other instances it is an array.
My Android Studio is giving me the following error when I try to parse the json with Gson into my data model using the following line of code:
gson.fromJson(result.toString(),Response.class);
It appears to be failing on an instance where "sets" is shown an empty string rather than an object:
Expected BEGIN_OBJECT but was STRING at line 1 column 942 path $.setlists.setlist[0].sets
Does anyone have advice on how to handle this type of thing? I've noticed it with all artists I've looked up so far.
Thanks!
Assuming Response is a class you wrote containing the main fields of the json and that at some point in it you have:
#SerializedName("setlist")
private List<MyItem> setlist;
I also assume your MyItem class contains the field:
#SerializedName("sets")
private List<MySet> sets;
if you let Gson parse it it will fail when it found a string instead of a list (-> array) of MySet object.
But you can write a custom TypeAdapter for your MyItem.
There's plenty of documentation about how to write a Gson TypeAdapter, look for it.
Use instanceOf operator to determine the type and cast accordingly.
JSONObject response=new JSONObject(res);
if(res.get("key") instanceOf JSONObject)
{
// code for JSONObject
}
else if(res.get("key") instanceOf JSONArray)
{
// code for JSONOArray
}
And so on

Force YAML Tag on JavaBean properties

I have been using SnakeYAML for certain serialization/deserialization. My application combines Python and Java, so I need some "reasonable behaviour" on the Tags and the Types.
My problem / actual status on the YAML document:
!!mypackage.MyClassA
someFirstField: normal string
someSecondField:
a: !!mypackage.ThisIsIt
subField: 1
subOtherField: 2
b: !!mypackage.ThisIsIt
subField: 3
subOtherField: 4
someThirdField:
subField: 5
subOtherField: 6
I achieved the use of the tags inside collections (see example someSecondField) by reimplementing checkGlobalTag and simply performing return. This, if I understood correctly, ensures no smart cleanness of snakeyaml and maintains the tags. So far so good: I need the type everywhere.
However, this is not enough, because someThirdField is also a !!mypackage.ThisIsIt but it has implicit tag and this is a problem (Python does not understand it). There are some other corner cases which are not to the point (tried to take some shortcuts in the Python side, and they became a Bad Idea).
Which is the correct way to ensure that the tags appear for all user-defined classes? I assume that I should override some methods on the Representer, but I have not been able to find which one.
The line responsible for that "smart tag auto-clean" is the following:
if (property.getType() == propertyValue.getClass())
Which can be found in representJavaBeanProperty, for the class Representer.
The (ugly) solution I found is to extend the Representer and #Override the representJavaBeanProperty with the following:
protected NodeTuple representJavaBeanProperty(Object javaBean,
Property property,
Object propertyValue,
Tag customTag) {
// Copy paste starts here...
ScalarNode nodeKey = (ScalarNode) representData(property.getName());
// the first occurrence of the node must keep the tag
boolean hasAlias = this.representedObjects.containsKey(propertyValue);
Node nodeValue = representData(propertyValue);
if (propertyValue != null && !hasAlias) {
NodeId nodeId = nodeValue.getNodeId();
if (customTag == null) {
if (nodeId == NodeId.scalar) {
if (propertyValue instanceof Enum<?>) {
nodeValue.setTag(Tag.STR);
}
}
// Copy-paste ends here !!!
// Ignore the else block --always maintain the tag.
}
}
return new NodeTuple(nodeKey, nodeValue);
This also forces the explicit-tag-on-lists behaviour (previously enforced through the override of the checkGlobalTag method, now already implemented in the representJavaBeanProperty code).

Error reading objects from Gemalto smartcard using IAIK pkcs11wrapper

I'm trying to read the public certificate names from a smartcard to display to the user before they sign a file using a gemalto smartcard.
I've followed the getInfo example from iaikPkcs11Wrapper demos as below :
Module pkcs11Module = Module.getInstance(settings.getCryptoDll());
Slot[] slotList;
try{
slotList = pkcs11Module.getSlotList(true);
}catch(TokenException tex){//module is not initialised
tex.printStackTrace();
pkcs11Module.initialize(new DefaultInitializeArgs());
slotList = pkcs11Module.getSlotList(true);
}
for (Slot slot : slotList) {
Token token = slot.getToken();
iaik.pkcs.pkcs11.Session session = token.openSession(true, SessionReadWriteBehavior.RO_SESSION, null, null);
session.findObjectsInit(null);
Object[] objects = new Object[0];
try {
objects = session.findObjects(1);
This fails always at the line objects = findObjects(1); with a CKR_TEMPLATE_INCONSISTENT exception.
As I understand from the documentation session.findObjectsInit(null) should just return all accessible objects on the card and you can then compare them for type.
I have various smartcards and they all fail like this, I've also tried calling session.findObjectsInit(tempObj) with a GenericTemplate object and a X509PublicKeyCertificate which both return the same exception, and with an X509AttributeCertificate which returns no objects but does not throw the exception.
I'd appreciate any pointers anyone can give. Or do I need to create a matching template object using GenericTemplate? I'm unsure why I'm getting the exception as I thought passing the object into the getObjectInit method filtered for thet object so anything returned should match.
EDIT
I've subsequently tried with other templates and ones for objects not on the card just return an empty array- no exception and ones I think are on the cards just throw the ckr_template_inconsistent exception, any help would be gratefully received.
EDIT2
I've now tried with some new 'V3' cards, which do infact work, all my test cards work using another technique (we currently use capicom via com4J for signing), so maybe there is an issue with the iaik wrapper, or gclib.dll (or me).

json parsing problems

data: [
{
type: "earnings"
info: {
earnings: 45.6
dividends: 4052.94
gains: 0
expenses: 3935.24
shares_bought: 0
shares_bought_user_count: 0
shares_sold: 0
shares_sold_user_count: 0
}
created: "2011-07-04 11:46:17"
}
{
type: "mentions"
info: [
{
type_id: "twitter"
mentioner_ticker: "LOANS"
mentioner_full_name: "ERICK STROBEL"
}
]
created: "2011-06-10 23:03:02"
}
]
Here's my problem : like you can see the "info" is different in each of one, one is a json object, and one is a json array, i usually choose Gson to take the data, but with Gson we can't do this kind of thing . How can i make it work ?
If you want to use Gson, then to handle the issue where the same JSON element value is sometimes an array and sometimes an object, custom deserialization processing is necessary. I posted an example of this in the Parsing JSON with GSON, object sometimes contains list sometimes contains object post.
If the "info" element object has different elements based on type, and so you want polymorphic deserialization behavior to deserialize to the correct type of object, with Gson you'll also need to implement custom deserialization processing. How to do that has been covered in other StackOverflow.com posts. I posted a link to four different such questions and answers (some with code examples) in the Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied thread. In this thread, the particular structure of the JSON objects to deserialize varies from the examples I just linked, because the element to indicate the type is external of the object to be deserialized, but if you can understand the other examples, then handling the problem here should be easy.
Both key and value have to be within quotes, and you need to separate definitions with commas:
{
"key0": "value0",
"key1": "value1",
"key2": [ "value2_0", "value2_1" ]
}
That should do the trick!
The info object should be of the same type with every type.
So check the type first. Pseudocode:
if (data.get('type').equals("mentions") {
json_arr = data.get('info');
}
else if (data.get('type').equals("earnings") {
json_obj = data.get('info');
}
I'm not sure that helps, cause I'm not sure I understand the question.
Use simply org.json classes that are available in android: http://developer.android.com/reference/org/json/package-summary.html
You will get a dynamic structure that you will be able to traverse, without the limitations of strong typing.....
This is not a "usual" way of doing things in Java (where strong typing is default) but IMHO in many situations even in Java it is ok to do some dynamic processing. Flexibility is better but price to pay is lack of compile-time type verification... Which in many cases is ok.
If changing libraries is an option you could have a look at Jackson, its Simple Data Binding mode should allow you to deserialize an object like you describe about. A part of the doc that is probably quite important is this, your example would already need JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES to work...
Clarification for Bruce: true, in Jackson's Full Data Binding mode, but not in Simple Data Binding mode. This is simple data binding:
public static void main(String[] args) throws IOException {
File src = new File("test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature. ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
Object root = mapper.readValue(src, Object.class);
Map<?,?> rootAsMap = mapper.readValue(src, Map.class);
System.out.println(rootAsMap);
}
which with OP's sightly corrected sample JSON data gives:
{data=[{type=earnings, info={earnings=45.6, dividends=4052.94, gains=0,
expenses=3935.24, shares_bought=0, shares_bought_user_count=0, shares_sold=0,
shares_sold_user_count=0}, created=2011-07-04 11:46:17}, {type=mentions,
info=[{type_id=twitter, mentioner_ticker=LOANS, mentioner_full_name=ERICK STROBEL}],
created=2011-06-10 23:03:02}]}
OK, some hand-coding needed to wire up this Map to the original data, but quite often less is more and such mapping code, being dead simple has the advantage of being very easy to read/maintain later on.

Categories