I'm using Spring to manage communications between my Android client and a Java backend. In particular the class MappingJackson2HttpMessageConverter does the job of converting JSON to Java objects back and forth on Android.
My issue is the following: sometimes I need to update the app, which often results in additional fields to be added to some of the classes which build my model, and as a consequence additional fields in the JSON data that travels between the clients and my server. When I do that it would be crucial for the "old" versions of the app to remain compatible with the new, slightly enhanced, object model. In particular, if the server sends to the client a JSON payload with too many fields (compared to what the client "knows"), the client should just ignore those fields without complaining that it cannot create the object properly. Unfortunately this is not the case now, since if the server sends an additional field, say called "country", the client throws the following exception when trying to convert the object:
Could not read JSON: Unrecognized field "country" (class com.example.MyUser), not marked as ignorable (19 known properties: ...)
Thanks for any help!
Use #JsonIgnoreProperties annotation
This advice will sound slightly trollish, but its honest advice- don't use Spring. Complicated frameworks like that just cause more problems than they're worth unless you want to use them exactly the way the devs envisioned. They also make your app slow as hell. You're better off without them, you'll spend more times working around problems like this than they save you.
Related
I know enums are used when we are expecting only a set of values to be passed. We don't want the caller to pass anything other than the well defined set.
And this works very well inside a project. Because you know what you've to pass.
But consider 2 projects, I am using the models of 1st project in 2nd.
Second project has a method like this.
public void updateRefundMode(RefundMode refundMode)
enum RefundMode("CASH","CARD","GIFT_VOUCHER")
Now, I realise RefundMode can be PHONEPE also, So If I start passing this to 1st project, it would fail at their end (Unable to desirialize enum PHONEPE). Although I've added this enum at my end.
Which is fine, because If my first project doesn't know about the "PHONEPE", then it doesn't know how to handle it, so he has to update the models too.
But my problem is, Let's imagine a complex Object am trying to pass, which also takes this RefundMode, when I pass a new RefundMode just this field should be become null or ignored at their end right ? Rather than not accepting the whole object, and breaking the entire flow/request.
Is there a way I can specify jackson (jsonproperties) to just ignore that field if an unknown value is being passed. Curious to know.. (Although In that case, I am breaking the rule of ENUM) So, why not keep a String which solves all the problem ?
It's all about contracts.
When you are in a client/server situation, being a mobile app and a web server, or a Java library (jar) and another Java project, you have to keep the contracts in mind.
As you observed, a change in contracts need to be propagated to both parties: the client and the server (supplier).
One way of working with this is to use versioning. You may say: "Version 1: those are the refund modes.". Then the mobile app may call the web server by specifying the contract version in the URL: /api/v1/refund?mode=CASH
When the contract needs to be changed, you need to consider what to do with the clients. In the case of mobile apps, the users might not have updated their app to the latest version, so their app may still be calling /api/v1 (and not supporting new refund modes). In that case, you may want to support both /api/v1 and /api/v2 (with the new refund mode) in your web server.
As your example shows, it is not always possible to transparently adapt one contract version to another (in your example, there is no good equivalent to PHONEPE in the original enum). If you have to deal with contract updates, I suggest explicitly writing code to them (you can use dedicated JSON schemas, classes and services) instead of trying to bridge the gaps. Think of what would happen with a third, fourth version.
Edit: to answer your last question, you can ignore unknown fields in JSON by following this answer (with the caveats explained above): https://stackoverflow.com/a/59307683/2223027
Edit 2: in general, using Enums is a form of strong typing. Sure, you could use Strings, or even bits, but then it would be easier to make mistakes, like using GiftVoucher instead of GIFT_VOUCHER.
I'm trying to learn Spring Boot by implementing a simple REST API.
My understanding was that if I need to transfer an object over the wire, that object should implement Serializable.
In many examples on the net though, including official ones, domain classes that need to be transferred from server to client (or vice-versa) do not to implement Serializable.
For instance: https://spring.io/guides/gs/rest-service/
But in some cases, they do:
For instance: https://github.com/szerhusenBC/jwt-spring-security-demo/blob/master/src/main/java/org/zerhusen/security/JwtAuthenticationRequest.java
Is there a general rule of thumb on when to implement Serializable?
To update this, advice about Serializable has changed, the recommendation currently seems to be Don’t use Serializable for anything.
Using the Java serialization API means you need something in Java on the other side of the wire to deserialize the objects, so you have to control the code that deserializes as well as the code that serializes.
This typically isn't relevant for REST applications, consuming the application response is the business of someone else's code, usually outside your organization. When building a REST application it's normal to try to avoid imposing limitations on what is consuming it, picking a format that is more technology-agnostic and broadly available.
Some reasons for having an object implement java.io.Serializable would be:
so you can put it in an HttpSession
so you can pass it across a network between parts of a distributed application
so you can save it to the file system and restore it later (for instance, you could make the contents of a queue serializable and have the queue contents saved when the application shuts down, reading from the save location when the application starts to restore the queue to its state on shutdown).
In all these cases, you serialize so you can save something to a filesystem or send it across a network.
There are many ways to serialize an object. Java's object serialization is just one of them. From the official documentation:
To serialize an object means to convert its state to a byte stream
REST APIs usually send and receive JSON or XML. In that case serializing an object means converting its state to a String.
There is no direct connection between "sending an object over the wire" and implementing Serializable. The technologies you use dictate whether or not Serializable has to be implemented.
The specific examples you have mentioned do not transfer objects over the wire. From the example links I see that the controller methods return a domain object with ResponseBody annotation. Just because the return type of the method is the domain object it is not necessary that the whole object is being sent to the client. One of the handler method in Spring mvc framework internally intercepts the invocation and determines that the method return type does not translate to direct ModelAndView object. RequestResponseBoodyMethodProcessor which handles the return value of such annotated methods and uses one of the message converters to write the return object to the http response body. In the case the message converter used would be MappingJackson2HttpMessageConverter. So if are to follow the same coding style you are not required to implement Serializable for your domain objects.
Have a look at this link for the Http message converters provided by default from spring. The list is quiet extensive however not exhaustive and if requirements arise you can implement your own custom message converter to user as-well.
that's a good question when to implement Serializable interface.
these links can provides some useful contents:
Serializing java.io.Serializable instance into JSON with Spring and Jackson JSON
When and why JPA entities should implement the Serializable interface?
I sometimes wonder about this, and I think
Because Java is a open source language, and more libraries providered by third party. for tells who will serialize and deserialize the object, the java offical declare a constract interface, makes transfer easy and safety throught different library.
It's just a constract, most third-party libraries can serialize/deserialize when checking implement this constract. and jackson's jar library is not use it.
So you can deem if you use serialize/deserialize object data in your own system, and simple process, likes just serialize and response it(jackson in spring MVC), you needn't to implements it.
but if you used in other jar library, likes saving in HttpSession, or other third-party componens/library, you should(or have to) implement Serializable, otherwise the libraries will throw a exception to tell you the constract interfaced which it knows is not provide.
But they said it's a good habit and best properties that to implement the Serializable when serialize a custom class. :)
you should serialize if you are using caching for database operations.Usually the third party cache providers like (hazle cast, Jboss cache etc..) internally serialize/ de serialise objects.In that case model classes should implement Serializable to facilitate caching.
I have recently upgraded to Genson 1.3 and I am not 100% sure if this issue is new or not as previously I patched the 0.98 version to make it work.
Context
We are using our own implementation of the BeanMutatorAccessorResolver. This is so that we can dynamically decide whether a property should be serialized or not. Basically we have integrated Genson into our generic jersey REST API interface. Genson does all the serializing and deserializing. When doing a GET requests it is possible for a user to pass fields in the URL in order to filter those he specifically needs (especially for large objects this is necessary where you only need 3 fields or so for displaying a table overview). For example: ?fields=field1, field2, field3. We then know in our implementation of BeanMutatorAccessorResolver exactly which fields to serialize and which ones to ignore. This is mainly intended for speeding up requests and parsing as we are then working with less data.
Problem
Unfortunately it seems that once Genson has read in all the fields via reflection or whatever, it caches that. This would be no problem if we were always requesting the same fields. Unfortunately on some occasions we need more fields then before, but because Genson does not visit our BeanMutatorAccessorResolver a second time it only returns the few fields that it has already cached.
Is there anyway around this? Perhaps there is a better solution than turning cahing off completely - because that would most probably hurt performance, right?
Update
Is seems that I have found the location where this is happening. Basically Genson returns a cached converter in Genson.provideConverter(Type forType) (line: 154).
Converter<T> converter = (Converter<T>) converterCache.get(forType);
At the top of the method I have noticed that it looks for a __GENSON$DO_NOT_CACHE_CONVERTER.
if (Boolean.TRUE.equals(ThreadLocalHolder.get("__GENSON$DO_NOT_CACHE_CONVERTER", Boolean.class))) {
Should I perhaps set this value or is there a better solution?
The problem has been solved thanks to Eugen. The solution can be found here: https://groups.google.com/forum/#!topic/genson/Z1oFHJfA-5w.
Basically you need to extend 3 classes to get this working:
GensonBundle, which you can register with the GensonBuilder.
BaseBeanDescriptorProvider, which gets created in GensonBundle.
BeanDescriptor, which gets created in BaseBeanDescriptorProvider and
which contains the serialize method to adapt to your needs.
I'm reading the two introductory articles about bulding and consuming Spring Rest web services.
What's weird - they're creating a Greeting representation class in the client app (second link ref) for storing the GET response (the greetingmethod on server side returns a Greeting object). But the Greeting classes on the server and client side are different classes - well, they are two distinct classes with identical names, identical field names and types (client's doesn't have a constructor).
Does it mean I have to similarly rewrite the class from stratch when building the client app? In order to do that, I'd need specs on what are the fields' types of JSON-packed objects passed by server's app. A server serializes the object of class ABCClass to JSON and sends it to client. Even if some field called 'abc' has value 10, it doesn't make it an integer. Next time it might contain a string.
My question is - how much information from server app's devs do I need in order to create a client application? How is it usually done?
It all depends on your deserializer and on your needs. With Jackson for example you might use mixins (wiki ref) and custom deserializers (wiki ref) that build your object with your required field names and your structure.
Its just simplest way to have same field names and structure, but not the only one.
Of course, however, you should know the server reply structure to deserialize it anyway
(Code is for Android Actually, I need code to be portable between Android and Java SE.)
I want to have a "settings" class with various game settings, like
public int map_size;
public String server_name;
etc.
The data needs to be accessed fairly frequently (so members, not a key-value map), and from time to time de/serialized in some standard way (mainly to send it through network).
I want to be able to
Serialize and deserialize the object into XML or JSON, without having to explicitly write the code for every member (but still having some degree of control over the format).
Define some (constant) meta-data about every member (default value, GUI name, XML identifier, ...), in a way that allows for easy modification in the source code (I want to be able to add a new meta-property, define a default value for it, and not have to specify it everywhere else).
1 is achievable by using reflection. I thought Java annotations for class members would be perfect for 2:
#Setting(id = "server_name", name = "Server title", default = "Server0")
public String server_name;
But it looks like (user-defined) annotations don't work in Android yet - code using them crashes the compiler...
What would be the easiest way to store the meta-data about the settings (or another way to approach all this)?
Store information about settings in some external XML file?
Store it in a Java data structure, with content defined in the code? Defining the data in this way somehow seems very unwieldy, especially compared to keyword arguments of annotations.
?
FYI, it looks like Jackson was fixed to work with Android in the Jackson 0.9.7 release.
Though I agree with Daniel Lew that using the built-in Android preferences is the best solution for an Android client. For a JavaSE client the Properties class is a good way to store preferences. There's also a JavaSE preferences package, but it may do more then you need.
Is there any particular reason you're not using built-in Android preferences? As long as all the game settings are primitives (or Strings) then that's probably the easiest way to store preferences. Also, it synchronizes well with PreferenceActivity if you end up making a settings page (there are some Preference examples in the ApiDemos).
While I'm not sure how well they work on Android, XStream or Jackson provide highly customizable XML or JSON (de)serialization of Java objects. Note that XStream supports both XML and JSON output, Jackson is just JSON.