I know there are numerous posts out there for a similar problem, but mine seems to be a bit different. I am reading in a bunch of JSON and would like to build POJO from it, but I don't want to use the names of the JSON result. Is there a way to "map" the element names in JSON to the attributes in my POJOs (using gson or Jackson maybe)?
It's worth mentioning this application is being built for Android.
Thanks in advance!
If you're using Gson, you can append an attribute to your objects, like so:
#SerializedName("ServicesResult")
public String services;
Where "ServicesResult" is the actual name of the element in the JSON.
With Jackson, you have multiple options:
Use #JsonProperty("name") annotation to indicate name to use in JSON, add directly or use mix-in annotations (external)
Specify PropertyNamingStrategy to convert from "Java name" to "JSON name" (there is default java<->c-style converter bundled with 1.9)
Modify AnnotationIntrospector to change the name using some other mechanism than annotations
Jackson will also interpret the Basic package javax.xml.bind.annotation
If you use those annotations you can readily move between Json/XML
Related
This seems like it would be a really common thing to need in just about any Java project. And yet I am unable to find anything that serves this purpose.
I used to use a web framework called Stripes Framework, that had annotation driven validators and automatic formatting via their validator API.
Example:
#Validate(maxlength = ModelConstants.NAME_MAX_LENGTH, converter = CapitializeFullyTypeConverter.class)
private String name;
#Validate(maxlength = ModelConstants.NAME_MAX_LENGTH, converter = EmailTypeConverter.class)
private String email;
Those fields would be defined on your controller action bean, and all user input would automatically be validated and formatted according to the specified rules.
If someone would enter their email address as: "TEST#TEST.COM"
Then it would automatically be formatted to: "test#test.com"
I would like to find something like this for automatically formatting data within DTOs.
If nothing like this is available, what is the usual way of handling this? Surely everyone is not writing custom formatting functions for each getter within the DTO?
Assumption: meaning of "formatter" as type-converter
When you ask for annotation based "formatter" you mean Stripe Framework's #Validate annotation with its parameter converter. The converter can be parameterized as:
(class) The converter class that will be used to transform this parameter into its object representation
In the Web-MVC context this means the converter is used to convert the request-parameter, exactly its source value, as supplied by the incomming web-request. The converted value is then stored as target value to the (DTO) object's property.
Example: Conversion of (DTO) Strings
Web request is given incommong with parameter name email and value string TEST#EXAMPLE.COM. This should the be converted to lowercase and strored in the DTO's property (a.k.a attribute or field ) email as value test#example.com.
Spring annotations for DTOs
Spring Framework also uses the concepts of request validation and request conversion. It also allows to configure these annotations-driven on the DTOs or classes and their attributes.
The validation leverages Java Bean Validation standard (JSR-303) javax.validation annotations like #Valid and #Length.
The conversion is part of the HttpConverters used for serialization/deserialization of responses/requests to/from objects (DTO). Therefore Spring allows to inlude object-relational mapper (ORM) frameworks or libraries as (e.g. Maven) dependencies. These bring their own annotations regarding conversation with them.
Fasterxml's Jackson
Jackson (ORM) for example uses the annotation #JsonFormat to achieve simple string conversions - but only for non-string fields like Date or Number (as far as I know).
It also allows complete customisation of serializers and deserializers via annotations #JsonSerialize and #JsonDeserialize.
Note, that although many annotations in Jackson are named with "Json" they mostly also apply to XML or even other data formats (representations) like CSV, etc.
String To Lowercase with Jackson
Your question was asked for Jackson: How to force Jackson deserialize field values to lower case and answered.
See also
Difference between #Valid and #Validated in Spring
Use Jackson to deserialize JSON string or object into a String field
DZone: Tutorial on Jackson Deserialization Annotations
Bealdung (2019): Getting Started with Custom Deserialization in Jackson
If you are using Spring Mvc, you have access to a formatting API.
There are pre-existing annotations in the org.springframework.format.annotation package for date and number formatting.
If you need custom formatting rules, you can write your own and register it via the FormattingConversionServiceFactoryBean.
See some examples here: https://docs.spring.io/spring-framework/docs/3.2.0.RC1/reference/html/validation.html
I realize this has probably been asked a hundred times but I have searched a lot and can't find specifically what I'm looking for.
Here is what I'd like. Given a string data, I'd like to deserialize into an object obj that doesn't have all the fields predefined. I'd like to just be able to ask for the fields I want such as obj.getString("stringFieldName") or obj.getInt("intFieldName"). I already have gson being used for other things so if it is possible with gson that would be great although not opposed to using another library.
The 'standard' Android JSON library (since API 1) already provides such untyped access.
See JSONObject, eg. getInt:
Returns the value mapped by name if it exists and is an int or can be coerced to an int, or throws otherwise.
Unless needing the JSON mapped onto a 'native' Java collection type this is probably the simplest way to achieve the request. It doesn't require any additional libraries.
With Jackson library you can annotate data model class with
#JsonIgnoreProperties(ignoreUnknown = true)
and the jacksonconverter will just parse only these fields that you defined. Other will be ignored.
Have you tried using Retrofit from Square? It works with GSON and Java Annotations and it's super easy to set up.
I'm using Jackson to deserialize some JSON into Java POJOs. I register the MrBean module with my object mapper, so all I have to do is define a bunch of interfaces, and the POJOs are generated automagically, based on those interfaces.
I would like to have a Credentials interface with various types of credentials that extend it, e.g. UsernamePasswordCredentials and CertificateFileCredentials.
Doing this without any annotations or other incantations to try to make it work gives me the following error in my unit test:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "username" (Class org.codehaus.jackson.generated.SCRUBBED.Credentials), not marked as ignorable
at [Source: java.io.StringReader#e0b6f5; line: 32, column: 29] (through reference chain: HostConfiguration["hostDefinitions"]->HostDefinition["credentials"]->Credentials["username"])
I've also followed the instructions at another StackOverflow post, and I'm getting the same error.
The error makes sense; Jackson is trying to map the contents of my JSON file to an empty interface. However, I (naively, perhaps) expected Jackson to look for interfaces that extend the base Credentials interface and try to match up the fields in those interfaces to the fields it found in the JSON object.
I've seen some examples at the Jackson wiki that make use of meta-information in the JSON object, e.g. decorating an object with "#class":"foo.bar.CertificateFileCredentials", but I'd prefer to avoid any of that since my JSON input will be generated automatically by other services, and those other services shouldn't have to know anything about the internals of my service.
Thanks!
How would you define actual implementation classes? As additional interfaces? Those should get generated correctly; but the problem is during deserialization: there must be some way for deserializer to find out actual type to use, if there are multiple choices.
For this, #JsonTypeInfo is recommended to be used as you have noticed.
Actually, the technique would work well for your purposes too, even though you don't control the service that generates the JSON.
Saving the class name is a nice easy default when using #JsonTypeInfo but Jackson lets you customize this to your liking.
For example, suppose the service generates JSON that looks like this:
{ meows: 400, furColor: "green", species: "cat" }
Then you can define these interfaces to convert it properly.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY,property="species")
#JsonSubTypes({
#JsonSubTypes.Type(value=Feline.class, name="cat")
})
public interface Animal {
public String getFurColor();
}
#JsonTypeName("cat")
public interface Feline extends Animal {
#JsonProperty("meows") // just to have an example of a renamed property...
public long getMeowingVolumeInDecibels();
}
Then you should just automatically get the right java type at runtime when deserializing, as well as automatically generate the "species" property depending on the runtime type. Hope that helps!
I have an Java class, like Library, that contains many fields. I want do ajax call to server
and in controller's method I want to have partly initialized #RequestBody Library with only
fields, which are present in json object.
I read the http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/, but I need not full object.
Please Help
You could use a org.codehaus.jettison.json.JSONObject (part of the Jettison project) and only include the fields that you need.
Or, you could just make a simplified version of Library that includes only the fields that you want (call it AjaxLibrary or something).
It would not be a problem to use full object, cause fields would not be initialized, if they are not present at entire json.
Also you can create own DTO class, e.g. SomeActionLibraryDTO. Extract required fields from Library, and use #JsonIgnoreProperties(ignoreUnknown = true) annotation for class to ignore the rest of json object (I suppose you are using the default json jackson marshaller, right?)
I'm using GSON to convert JSON data I get to a Java object. It works pretty well in all my tests.
The problem is that our real objects have some properties named like is_online. GSON only maps them if they are named totally equal, it would be nice to have GSON convert the names to Java camel case isOnline.
It seems this is possible while creating the JSON data, camel case is converted to underscore separated words in JSON. But I can't find a way to specify this the other way round.
I have found the following setting works perfect when reading json with underscored attributes and using camelcasing in my models.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()
You can use the SerializedName annotation:
#SerializedName("field_name_in_json")
private final String fieldNameInJava;
Note: When you have set a FieldNamingPolicy already, SerializedName will overwrite its settings for that specific field (quite handy for special cases).
Bear in mind your example is an edge case. If you have a property 'foo' its getter should be named 'getFoo', and if you have a property named 'foo_bar' its getter should be named 'getFooBar', however, in your example you're mapping a boolean and booleans have special case naming conventions in java. A primitive boolean property named online should have a getter named 'isOnline', NOT 'getOnline' or even worse, 'getIsOnline'. A boolean wrapper object (i.e. Boolean) should not follow this special case and a property named 'online' should have a getter named 'getOnline'.
Hence, having boolean properties with 'is' in the name is an edge case, where you'll want to strip out this particular prefix during your conversion. In the reverse direction, your code may want to inspect the json object for both a raw property name as well as a 'is_XXX' version.
I think what you want is here. Using annotations you can tell GSON that the mySuperCoolField is actually called this_field_is_fun in the JSON and it will unpack it correctly. At least I think it works for deserialization too.
If that doesn't work, you can use custom JsonSerializer/JsonDeserializers, which work great, but you have to update them for changes in your class (like when you add a field). You lose the auto-magic.
The easiest thing to do (which would be ugly, but very clean and simple if the first suggestion doesn't work) would be to simply name the field in a way to make GSON happy, and add extra accessor methods with the names you like, e.g.
public boolean isXXX() {return this.is_XXX;}