I use ARCore in a project and need to save the state from ARCore to use it at a later stage. The problem is that ARCore doesn't give any functions to set state. The idea then is to serialize the Session object and then deserialize it when needed.
I first tried to create a subclass of Session which implements Serializable, but that gave multiple NotSerializableException errors. Now I'm trying to solve this problem with Gson, using its ExclusionStrategy, to exclude the classes that aren't serializable. I'm not sure though how to approach this.
In MainActivity:
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(new Strategy())
.create();
String jsonString = gson.toJson(session);
Strategy:
#Override
public boolean shouldSkipField(FieldAttributes field) {
return field.getDeclaredType().equals(** WHAT TO PUT HERE **.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
I want the Session object serialized into a JSON object to be able to store it.
I don't think you'll be able to serialize your Session and recover it later. What you can do is store anchors informations to use it later. Services like AR Core Cloud Anchors and Azure Spatial Anchors can help you doing that.
Related
We are trying to create a Java client for an API created with Spring Data.
Some endpoints return hal+json responses containing _embedded and _links attributes.
Our main problem at the moment is trying to wrap our heads around the following structure:
{
"_embedded": {
"plans": [
{
...
}
]
},
...
}
When you hit the plans endpoint you get a paginated response the content of which is within the _embedded object. So the logic is that you call plans and you get back a response containing an _embedded object that contains a plans attribute that holds an array of plan objects.
The content of the _embedded object can vary as well, and trying a solution using generics, like the example following, ended up returning us a List of LinkedHashMap Objects instead of the expected type.
class PaginatedResponse<T> {
#JsonProperty("_embedded")
Embedded<T> embedded;
....
}
class Embedded<T> {
#JsonAlias({"plans", "projects"})
List<T> content; // This instead of type T ends up deserialising as a List of LinkedHashMap objects
....
}
I am not sure if the above issue is relevant to this Jackson bug report dating from 2015.
The only solution we have so far is to either create a paginated response for each type of content, with explicitly defined types, or to include a List<type_here> for each type of object we expect to receive and make sure that we only read from the populated list and not the null ones.
So our main question to this quite spread out issue is, how one is supposed to navigate such an API without the use of Spring?
We do not consider using Spring in any form as an acceptable solution. At the same time, and I may be quite wrong here, but it looks like in the java world Spring is the only framework actively supporting/promoting HAL/HATEOAS?
I'm sorry if there are wrongly expressed concepts, assumptions and terminology in this question but we are trying to wrap our heads around the philosophy of such an implementation and how to deal with it from a Java point of view.
You can try consuming HATEOS API using super type tokens. A kind of generic way to handle all kind of hateos response.
For example
Below generic class to handle response
public class Resource<T> {
protected Resource() {
this.content = null;
}
public Resource(T content, Link... links) {
this(content, Arrays.asList(links));
}
}
Below code to read the response for various objects
ObjectMapper objectMapper = new ObjectMapper();
Resource<ObjectA> objectA = objectMapper.readValue(response, new TypeReference<Resource<ObjectA>>() {});
Resource<ObjectB> objectB = objectMapper.readValue(response, new TypeReference<Resource<ObjectB>>() {});
You can refer below
http://www.java-allandsundry.com/2012/12/json-deserialization-with-jackson-and.html
http://www.java-allandsundry.com/2014/01/consuming-spring-hateoas-rest-service.html
I am currently developing a web application and I would like to make java objects persistent at the server so that they can be retrieved at any time. Since a database is an overkill for my application, I choose the easiest way of persisting java objects: serialization to xml or to bytes. Unfortunately a big part of the code I use are java classes which I cannot modify and these classes do not implement the interface 'serializable'. What are my options regarding to serializing objects of these classes, as well as other interacting objects of my own classes?
As I said in my comments, I'd go for a SerializationService which would find the proper Serializer<T> for every object you want to save.
Something like :
public interface Serializer<T> {
Serializable toSerializable(T objectToSerialize);
//to build a factory/service around it
boolean canDeserialize(Serializable serializedObject);
T fromSerializable(Serializable serializedObject);
}
And if you want a basic, concrete example : with the quite-common Path :
public class PathSerializer implements Serializer<Path> {
#Override
public Serializable toSerializable(Path objectToSerialize) {
return objectToSerialize.toString();
}
#Override
public Path fromSerializable(Serializable serializedObject) {
if(!canDeserialize(serializedObject)){
throw new IllegalArgumentException("Cannot deserialize this");
}
return Paths.get((String)serializedObject);
}
#Override
public boolean canDeserialize(Serializable serializedObject) {
return serializedObject != null && serializedObject instanceof String;
}
}
You could also very well store POJO containing the name your original object class and the list of parameters needed in its constructor an/or a map of its fields to be able to regenerate your objects by reflection.
It's all up to you and the complexity of your application.
I think JSON would be the go-to solution here. Take Googles GSON library for example. You don't need to annotate your classes, simply write
Gson gson = new Gson();
MyObj obj = gson.fromJson(jsonString);
String json = gson.toJson(obj);
For more general information about the JSON format see the official JSON documentation.
One option would be to extend the classes that you don't have access to, in order to save their internal state, and implement Serializable on those.
More info on this SO question:
Serializing a class variable which does not implement serializable
Besides this, I don't think there is any other option except building some wrappers and serializing the classes manually to XML or JSON.
It is okay to use Parcelable, Realm, and GSON in one project in Android development? I'm just wondering how to implement it simultaneously because each of these libraries/frameworks has different annotations when making a POJO. Another one is Realm and Parcelable both persist data, so do I need to implement both?
GSON used to have quirkiness with Realm and required the following config
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.create();
GSON uses field reflection to read data from objects, which means that on managed RealmObjects, your fields will be null value.
This is because GSON also does not offer the option of using accessors to obtain the data, but Realm proxies do not copy the data to memory.
If you need an object that can be sent through Retrofit with #Body annotation and is a managed RealmObject, when you need to do apiService.sendObject(realm.copyFromRealm(myObject));.
Parcelable is not necessary for RealmObject in most cases, because any object that is managed by the Realm is already persisted, and readily available anywhere as long as you have its primary key.
But if you need to make detached modifiable copies of data and you're bent on using an unmanaged instance of the class directly to build the object you intend to save, then you can easily create Parcelable class using Parceler library.
In short:
RealmObjects are easily persistable to Parcelable using Parceler, but you typically don't need it, you just send the primary key between Activities and not the whole object
GSON doesn't work well with managed objects, because GSON is kinda dumb so you need to make an in-memory copy first
Personally, I prefer to keep my API response and my RealmModels separate, it's easier if you rely on mapping to a more optimal schema.
This should be no problem cause you can use multiple annotations to one method or one class.
If an annotation have the same name, you should give it the exactly package name like #java.lang.Override
I am developing an Android app using GAE on Eclipse.
On one of the EndPoint classes I have a method which returns a "Bla"-type object:
public Bla foo()
{
return new Bla();
}
This "Bla" object holds a "Bla2"-type object:
public class Bla {
private Bla2 bla = new Bla2();
public Bla2 getBla() {
return bla;
}
public void setBla(Bla2 bla) {
this.bla = bla;
}
}
Now, my problem is I cant access the "Bla2" class from the client side. (Even the method "getBla()" doesn't exist)
I managed to trick it by creating a second method on the EndPoint class which return a "Bla2" object:
public Bla2 foo2()
{
return new Bla2();
}
Now I can use the "Bla2" class on the client side, but the "Bla.getBla()" method still doesn't exit. Is there a right way to do it?
This isn't the 'right' way, but keep in mind that just because you are using endpoints, you don't have to stick to the endpoints way of doing things for all of your entities.
Like you, I'm using GAE/J and cloud endpoints and have an ANdroid client. It's great running Java on both the client and the server because I can share code between all my projects.
Some of my entities are communicated and shared the normal 'endpoints way', as you are doing. But for other entities I still use JSON, but just stick them in a string, send them through a generic endpoint, and deserialize them on the other side, which is easy because the entity class is in the shared code.
This allows me to send 50 different entity types through a single endpoint, and it makes it easy for me to customize the JSON serializing/deserializing for those entities.
Of course, this solution gets you in trouble if decide to add an iOS or Web (unless you use GWT) client, but maybe that isn't important to you.
(edit - added some impl. detail)
Serializing your java objects (or entities) to/from JSON is very easy, but the details depend on the JSON library you use. Endpoints can use either Jackson or GSON on the client. But for my own JSON'ing I used json.org which is built-into Android and was easy to download and add to my GAE project.
Here's a tutorial that someone just published:
http://www.survivingwithandroid.com/2013/10/android-json-tutorial-create-and-parse.html
Then I added an endpoint like this:
#ApiMethod(name = "sendData")
public void sendData( #Named("clientId") String clientId, String jsonObject )
(or something with a class that includes a List of String's so you can send multiple entities in one request.)
And put an element into your JSON which tells the server which entity the JSON should be de serialized into.
Try using #ApiResourceProperty on the field.
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.