In the Play framework i have a few models that have fields which are object references to other models. When i use renderJSON, i don't want those object references to be included. Currently for my needs i create a separate view model class which contains the fields i want, and in the controller i create instances of this view class as needed. Ideally i would like to be able to use the model class itself without having to write the view class.
Is there a way to annotate a field so that it will not be serialized when using renderJSON?
because play uses Gson for its Json serialization you can try the following:
public static void test()
{
Object foo = new SomeObject("testData");
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.create();
renderJSON(gson.toJson(foo));
}
now each field marked as transient will not be serialized. There is also another (better) way. You can use the com.google.gson.annotations.Expose annotation to mark each field you want to serialize.
public static void test()
{
Object foo = new SomeObject("testData");
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
renderJSON(gson.toJson(foo));
}
Using FlexJSON with play is another option, explained in this article: http://www.lunatech-research.com/archives/2011/04/20/play-framework-better-json-serialization-flexjson
Not sure why no one has written the most direct solution to this answer so I will do it here:
Simply mark the fields you do not want serialized via Gson as transient.
Here's an example:
public class Animal
{
private String name = "dog";
transient private int port = 80;
private String species = "canine";
transient private String password = "NoOneShouldSeeThis";
}
None of the items which are marked transient will be serialized.
When deserialized they will be set to their default (class default) values.
Resulting JSON will look like the following:
{"name":"dog","species":"canine"}
For more information on transient you can see the SO
Why does Java have transient fields?
I would override renderJSON to check a the field name against a member array of serialization exclusions.
Related
I need to validate a JSON list similar to the following:
[{"op":"A","path":"C","value":"B"},...]
in a Spring MVC application - I am currently deserializing (using default Jackson) to an object along the lines of:
public class Operations extends ArrayList<Operation>{}
public class Operation {
#NotEmpty
public String op;
#NotEmpty
public String path;
public Object value;
public void setOp(String op)... and other getters/setters
}
but I cannot figure out how to get jsr303 validation provided by reference hibernate implementation to fire for the attributes of Operation.
I can get it to function if I wrap the list in a class but then I have an incorrect format for the JSON, ie something like:
{"ops":[{"op":"A",...},...]}
is it possible to validate the first object (Operations)? and if not is it possible to serialize the first format (ie the JSON list) to an object of the second format (ie a list wrapped in a placeholder object with a placeholder field)
Update
Having failed to find a way to trigger the jsr303 validation on a bare ArrayList I have written a custom jackson json deserializer to stick it into a containing object with an annotated field along the lines of
#JsonDeserialize(using=OperationsDeserializer.class)
public class Operations {
#NotEmpty
private ArrayList<Operation> ops;
public void setOps(ArrayList<Operation>ops)...
public ArrayList<Operation> getOps()...
}
This works but now any autogenerated documentation for my api is generating json examples with the dummy "ops" field in it - ie {"ops" : [ ... ] }
so the search for a method of triggering jsr303 validation on an ArrayList that is not a field of another object continues - perhaps there is a way to inject a proxy wrapping class at runtime that might work around this?
Use ObjectMapper.class. it has a method which will convert Json Object into Class Object
method is , new ObjectMapper().readValue(String str, Class<T> valueType)
So you can iterate your Object array, convert to string and pass it to this method to get your result.
so it would look like,
new ObjectMapper().readValue(object.toString, Operation.class);
I need to add new property to an object, when serializing to JSON. The value for the property is calculated on runtime and does not exist in the object. Also the same object can be used for creation of different JSON with different set ot fields (kind of having a base class with subclasses, but I don't want to create ones just for JSON generation).
What is the best way of doing that, which doesn't involve creation of custom serializer class, which will take care of serializing of whole set of object's fields? Or may be it is possible to inherit some "basic" serializer, and simply take it's output and add new field to it somehow?
I learned about mixins, and looks like it is possible to rename/hide some fields, however it seems not be possible to add an extra one.
Can you not just add a method in value class? Note that it does not have to be either public, or use getter naming convention; you could do something like:
public class MyStuff {
// ... the usual fields, getters and/or setters
#JsonProperty("sum") // or whatever name you need in JSON
private int calculateSumForJSON() {
return 42; // calculate somehow
}
}
Otherwise you could convert POJO into JSON Tree value:
JsonNode tree = mapper.valueToTree(value);
and then modify it by adding properties etc.
2021 calling...
Simplest way I found to do this is #JsonUnwrapped:
public class Envelope<T> {
#JsonUnwrapped // content's fields are promoted alongside the envelope's
public T content;
// Transmission specific fields
public String url;
public long timestamp;
}
This works (bi-directionally) so long as Envelope's fieldnames do not clash with those of content. Also has a nice feature of keeping the transmission properties at the end of the serialised JSON.
One option is to add a field for this property and set it on the object before writing to JSON. A second option, if the property can be computed from other object properties you could just add a getter for it, for example:
public String getFullName() {
return getFirstName() + " " + getLastName();
}
And even though there's no matching field Jackson will automatically call this getter while writing the JSON and it will appear as fullName in the JSON output. If that won't work a third option is to convert the object to a map and then manipulate it however you need:
ObjectMapper mapper //.....
MyObject o //.....
long specialValue //.....
Map<String, Object> map = mapper.convertValue(o, new TypeReference<Map<String, Object>>() { });
map.put("specialValue", specialValue);
You're question didn't mention unmarshalling but if you need to do that as well then the first option would work fine but the second two would need some tweaking.
And as for writing different fields of the same object it sounds like a job for #JsonView
In Jackson, I am using annotation #JsonTypeInfo to include polymorphism support.
If, I do not want to go with annotation based approach, I can use global default typing or override the type information handling module.
I have tried global type information but it is emitting type information for all non final type.
What I need ,
I want to include type information only for polymorphic type.
I want to change default format of type info (to key-value pair)
Is it possible to achieve above two points just by twitting global configuration?
If not, what extension point should I used used to customize type-information module ?
I have read JacksonAnnotationIntrospector is the class which deals with type info.
Should I customize it to achieve above mentioned two points?
Help with Example will be well and good.
You can use Jackson's DefaultTypeResolverBuilder for this purpose. Extend this class and override the useForType method appropriately. Here is an example that adds type information only for the classes belonging to the test.jackson package (and sub-packages):
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTypeResolverBuilder;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
public class CustomTypeResolverBuilder extends DefaultTypeResolverBuilder
{
public CustomTypeResolverBuilder()
{
super(DefaultTyping.NON_FINAL);
}
#Override
public boolean useForType(JavaType t)
{
if (t.getRawClass().getName().startsWith("test.jackson")) {
return true;
}
return false;
}
}
Now, consider that you have Foo.java in test.jackson package and Bar.java in org.myorg package, each containing an int variable called "integer" and a String variable called "string".
You can serialize objects of these two classes this way:
ObjectMapper objectMapper = new ObjectMapper();
TypeResolverBuilder<?> typeResolver = new CustomTypeResolverBuilder();
typeResolver.init(JsonTypeInfo.Id.CLASS, null);
typeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolver.typeProperty("#CLASS");
objectMapper.setDefaultTyping(typeResolver);
Foo foo = new Foo(10, "Foo");
Bar bar = new Bar(20, "Bar");
System.out.println(objectMapper.writeValueAsString(foo));
System.out.println(objectMapper.writeValueAsString(bar));
The corresponding output will be:
{"#CLASS":"test.jackson.Foo","integer":10,"string":"Foo"}
{"integer":20,"string":"Bar"}
You can also customize the name of the attribute that represents the type ("#CLASS" in the above example). Hope this helps!
You can use the Moonwlker library.
With it, you can create an ObjectMapper like this:
ObjectMapper objectMapper = new ObjectMapper();
MoonwlkerModule module =
MoonwlkerModule.builder()
.fromProperty("#CLASS").toSubclassesOf(Animal.class)
.build();
objectMapper.registerModule(module);
And then use that mapper to (de)serialize. The Moonwlker website contains more details and configuration options.
I am using jackson json api to map json data to java objects. All is well in case of same object attribute names with json attributes. Now i have a situation where i am getting json data attribute with -. (my-name).
In java we can't include - in variable names.
import org.codehaus.jackson.map.ObjectMapper;
private static final ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue("{my-name:\"abcd\"}", User.class);
public class User {private String my_name; /*get-set methods*/}
Is there anything i need to apply in User.class.
I don't want to change my code so much.
In your java class you can give any name as you like
Ex. private String myName;
But in the setter method just write:
#JsonProperty("my-name")
public void setMyName(String myName) {
this.myName = myName;
}
So I have a class that I was planning on using for simple JSON serialization.
public class Thing {
private int field1;
private String some_other_field;
private List<SubType> subs;
private list<AnotherType> another;
public String toJson() {
Gson g = new Gson();
g.toJson(this);
}
}
So the documentation shows that if you want to serialize generic types, you need to specify a TypeToken:
Type listtype = new TypeToken<List<SubType>>() {}.getType();
gson.toJson(subs, listtype);
But then, how does this work if I have a whole class I want to serialize for? Where do I get to specify the serialization type for those two List<> types so that I can just pass the whole object in and get a serialized output? Is that even possible?
From the doc it seems that if you serialize a complete object with toJson(...), it deals with the generics attributes properly.
toJson(Object)
"Note that this method works fine if the any of the object fields are of generic type, just the object itself should not be of a generic type"
What output did you get with your object ?