How to rename json object name with java annotation? - java

How to rename json object name with java annotation?
Object structure in java:
public class ParentClass {
private MyClass myClass;
}
public class MyClass {
private String name;
}
Json will have next view:
{
"myClass":{
"name":"value"
}
}
How can I change name of "myClass" using java/spring annotations, something like
#JsonObjectName("abc")
public class MyClass {
private String name;
}
and json will look like:
{
"abc":{
"name":"value"
}
}

Rename the variable:
private MyClass myClass;
To:
private MyClass abc;
This will yield the correct JSON-output without the use of annotations.
If you still want to use annotations and keep the name of the variable you can use #JsonProperty():
#JsonProperty("abc") // name of the property
private MyClass myClass;

#SerializedName("abc") is also possoble

It depends on the framework you are using. If you are using Jackson Library you can use:
public class ParentClass {
private MyClass myClass;
}
#JsonProperty("abc")
public class MyClass {
private String name;
}
If you are using Gson then
#SerializedName(value = "abc")
public class MyClass {
private String name;
}
Additionally in Gson if you want to use any alternate name for the field during deserialization we can use alternate as below:
#SerializedName(value = "abc", alternate ="xyz")
public class MyClass {
private String name;
}
alternate is to be used only at time of deserialization and GSON will only process/deserialize the last occurence of that field from JSON data.

Related

Use jackson annotation JsonUnwrapped on a field with name different from its getter

I have a class like:
class Car {
private Engine myEngine;
#JsonProperty("color")
private String myColor;
#JsonProperty("maxspeed")
private int myMaxspeed;
#JsonGetter("color")
public String getColor()
{
return myColor;
}
#JsonGetter("maxspeed")
public String getMaxspeed()
{
return myMaxspeed;
}
public Engine getEngine()
{
return myEngine;
}
}
and Engine class like
class Engine {
#JsonProperty("fueltype")
private String myFueltype;
#JsonProperty("enginetype")
private String myEnginetype;
#JsonGetter("fueltype")
public String getFueltype()
{
return myFueltype;
}
#JsonGetter("enginetype")
public String getEnginetype()
{
return myEnginetype;
}
}
I want to convert the Car object to JSON using Jackson with structure like
'car': {
'color': 'red',
'maxspeed': '200',
'fueltype': 'diesel',
'enginetype': 'four-stroke'
}
I have tried answer provided in this but it doesn't work for me as field names are different then getter
I know I can use #JsonUnwrapped on engine if field name was engine. But how to do in this situation.
provide #JsonUnwrapped and #JsonProperty together:
#JsonUnwrapped
#JsonProperty("engine")
private Engine myEngine;
You shall use the #JsonUnwrapped as follows in the Car class for the desired JSON object:
class Car {
#JsonUnwrapped
private Engine myEngine;
#JsonProperty("color")
private String myColor;
#JsonProperty("maxspeed")
private int myMaxspeed;
...
I think the best solution here would be to use #JsonValue annotation over the myEngineType attribute in your Engine class, it will only serialize this attribute instead of the whole Engine object.
So your code would be like this:
class Engine {
#JsonProperty("fueltype")
private String myFueltype;
#JsonValue
#JsonProperty("enginetype")
private String myEnginetype;
}
You can take a look at this answer for more details.

How do you send back a subset of a JPA entity that is owned by another entity?

I have an entity that owns another entity:
//psuedocode
public class ClassA{
private String name;
#OneToOne
private ClassB classb;
}
public class ClassB{
private String thing1;
private String thing2;
private String thing3;
}
When I retrieve ClassA objects, I don't want to see ClassB.thing3, but I do want to see thing1 and thing 2:
{
"name":"classa",
"classb":{
"thing1":"hi",
"thing2":"there"
}
}
But if I query for ClassB I want to see everything:
{"thing1":"hi",
"thing2":"there",
"thing3":"joseph"}
So I can't just put an ignore annotation over thing3, because then I'll ignore it on the second fetch. I tried a Converter<ClassB>, but that forces me to implement toString() and fromString() for the JSON, which dies on converting the JSON object to Java-side (the converter expects a String, but gets the object instead).
I want to avoid building/parsing the JSON object myself if possible to let my json provider do the work, if possible. I'm on Johnzon.
This is possible, you need to use #NamedEntityGraph,
This should help, http://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/
Something like this should be possible by querying using SELECT NEW, but you're going to need some new Classes for that ... and won't be passing your entities directly to JSON.
new Classes:
(pseudocode)
class ResultB {
String thing1;
String thing2;
public ResultB(ClassB classB) {
this.thing1 = classB.thing1;
this.thing2 = classB.thing2;
}
}
class ResultA {
String name;
ResultB resultB;
public ResultA(ClassA classA) {
this.name=classA.name;
this.resultB=new ResultB(classA);
}
}
Query:
select new ResultA(a) from ClassA a fetch join a.classB;
Then you can pass ResultA instead of ClassA to JSON.
PS: As mentioned in the comment above, I don't think NamedEntityGraphs are the way to go here
I would always fetch all the data from the database and let the filtering to be done by the JSON provider if you want to serialize it anyway. If you use Jackson you can simply add views to your fields:
public class ClassA {
#JsonView(Views.AlwaysInclude.class)
private String name;
#JsonView(Views.AlwaysInclude.class)
#OneToOne
private ClassB classb;
}
public class ClassB {
#JsonView(Views.AlwaysInclude.class)
private String thing1;
#JsonView(Views.AlwaysInclude.class)
private String thing2;
private String thing3;
}
public class Views {
public static class AlwaysInclude {
}
}
Later when you serialize your object you just need to use your view:
String result = mapper
.writerWithView(Views.AlwaysInclude.class)
.writeValueAsString(new ClassA());
When you want to serialize only ClassB then you shouldn't use views.
String result = mapper.writeValueAsString(new ClassB());

Jackson ignore all properties of superclass from external library

I am developing using an ORM where I extend a base orm class to create tables.
For example:
public class Person extends DbItem {
#JsonIgnore
private String index;
private String firstName;
private String lastName;
}
Problem is that when I use ObjectMapper to serialize, it tries to serialize the members of the DbItem class. Is there any simple way to prevent this? For example with an annotation.
I had a look at a similar problem Jackson serialization: how to ignore superclass properties but I was hoping it could be done simpler, and I'm not sure if I could do it as I can't change the superclass since it is in an external library.
You can use a Mix-in or #JsonIgnoreProperties
For the purposes of these examples, the base ORM class and extension are assumed to be:
public class DbItem {
public String dbPropertyA;
public String dbPropertyB;
}
and
public class Person extends DbItem {
public String index;
public String firstName;
public String lastName;
}
respectively.
Using a Mix-in
A Mix-in is an abstraction of the de/serialization instructions that Jackson understands from an object itself. It is a way to customize de/serialization of 3rd party classes. In order to define a Mix-in, an abstract class must be created and registered with the ObjectMapper.
Example Mix-in Definition
public abstract class PersonMixIn {
#JsonIgnore public String dbPropertyA;
#JsonIgnore public String dbPropertyB;
#JsonIgnore public String index;
}
Registering the Mix-in
#Test
public void serializePersonWithMixIn() throws JsonProcessingException {
// set up test data including parent properties
Person person = makeFakePerson();
// register the mix in
ObjectMapper om = new ObjectMapper()
.addMixIn(Person.class, PersonMixIn.class);
// translate object to JSON string using Jackson
String json = om.writeValueAsString(person);
assertFalse(json.contains("dbPropertyA"));
assertFalse(json.contains("dbPropertyB"));
assertFalse(json.contains("index"));
System.out.println(json);
}
#JsonIgnoreProperties
If you want to avoid creating a class and configuring the ObjectMapper, the #JsonIgnoreProperties annotation can be utilized. Simply annotate the class you are serializing and list the properties to exclude.
Example Serializable Object
#JsonIgnoreProperties({"index", "dbPropertyA", "dbPropertyB"})
public class Person extends DbItem {
public String index;
public String firstName;
public String lastName;
}
See It In Action
#Test
public void serializePersonWithIgnorePropertiesAnnotation() throws JsonProcessingException {
// set up test data including parent properties
Person person = makeFakePerson();
ObjectMapper om = new ObjectMapper();
// translate object to JSON string using Jackson
String json = om.writeValueAsString(person);
assertFalse(json.contains("dbPropertyA"));
assertFalse(json.contains("dbPropertyB"));
assertFalse(json.contains("index"));
System.out.println(json);
}
You want to do custom field level serialization. This will be a bit more work to maintain your code base, but is by far the simplest solution. See Jackson JSON custom serialization for certain fields for implementation details.

How to deserialize a generic object at runtime with Jackson

Say I have the following java classes (getters & setters omitted for brevity).
public class AllMyEvents {
private List<SomeEvent<?>> eventList;
}
public class SomeEvent<T> {
private long time;
#JsonProperty("event_type")
private String eventType;
#JsonProperty("event_data")
private T eventData;
}
public class BigEvent {
private List<SomeEvent<LittleEvent>> subEvents;
}
public class LittleEvent {
private long data;
}
When I call:
ObjectMapper om = new ObjectMapper();
AllMyEvents events = om.readValue(IOUtils.toString(jsonData, "UTF-8"),AllMyEvents.class);
The field eventData is of type LinkedHashMap. What I want is for this fields type to be specified by the eventType string. If the string is 'big' I want eventData to have type BigEvent or LittleEvent if the string is 'little'.
Is it possible to do this with Jackson annotations, or will I need to write a custom serializer/deserializer, or some other method? I'm using Jackson 1.9 if that is relevant.
Json Sub types is your answer.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="#class")
#JsonSubTypes({
#JsonSubTypes.Type(value=BigEvent.class, name="big"),
#JsonSubTypes.Type(value=LittleEvent.class, name="little")
})
public class SomeEvent<T> {
private long time;
#JsonProperty("event_type")
private String eventType;
...
Also see: http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

How to deserialize JSON Array contained an abstract class without modifying a parent class?

I'm trying to deserialize JSON Array, which is persisted into my MongoDB, to a Java object by using Jackson. I found many tutorials mentioned to handle this polymorphism by adding:
#JsonTypeInfo(use=Id.CLASS,property="_class")
to a Super-class. However, in my case, I can't be able to modify the Super-class. So, are there some solutions to solve it without modifying the Super-class? Here is my code:
public class User {
#JsonProperty("_id")
private String id;
private List<Identity> identities; // <-- My List contains objects of an abstract class; Identity
public User(){
identities = new ArrayList<Identity>();
}
public static Iterable<User> findAllUsers(){
return users().find().as(User.class); // Always give me the errors
}
/*More code*/
}
It always give me the error - Can not construct instance of securesocial.core.Identity, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information.
You can use #JsonDeserilize annotation to bind a concrete implementation class to an abstract class. If you cannot modify your abstract class you can use the Jackson Mix-in annotations to tell Jackson how to find the implementation class.
Here is an example:
public class JacksonAbstract {
public static class User {
private final String id;
private final List<Identity> identities;
#JsonCreator
public User(#JsonProperty("_id") String id, #JsonProperty("identities") List<Identity> identities) {
this.id = id;
this.identities = identities;
}
#JsonProperty("_id")
public String getId() {
return id;
}
public List<Identity> getIdentities() {
return identities;
}
}
public static abstract class Identity {
public abstract String getField();
}
#JsonDeserialize(as = IdentityImpl.class)
public static abstract class IdentityMixIn {
}
public static class IdentityImpl extends Identity {
private final String field;
public IdentityImpl(#JsonProperty("field") String field) {
this.field = field;
}
#Override
public String getField() {
return field;
}
}
public static void main(String[] args) throws IOException {
User u = new User("myId", Collections.<Identity>singletonList(new IdentityImpl("myField")));
ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(Identity.class, IdentityMixIn.class);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(u);
System.out.println(json);
System.out.println(mapper.readValue(json, User.class));
}
}

Categories