I'm trying to override property name specified in #JsonProperty during serialization, but get both old and new named properties in the resulting json.
Entity:
class Bean {
#JsonProperty("p")
String prop;
#JsonCreator
Bean(#JsonProperty("p") String prop) {
this.prop = prop;
}
}
Serializing code:
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return "prop";
}
});
System.out.println(mapper.writeValueAsString(new Bean("test")));
Results in:
{"p":"test","prop":"test"}
Accrding to Jackson's code, this happens because constructor parameters are also annotated with #JsonProperty. I'm using Jackson 1.9.5.
Is there a way to disable constructor parameters and get {"prop":"test"} ?
Thanks for help in advance!
There is no way to directly disable annotations, but if you want to block their effects, you can sub-class JacksonAnnotationIntrospector, and override logic used for finding #JsonProperty annotation (or #JsonCreator).
Related
I have class with #JsonIgnore-d field:
public class MyClass {
...
#JsonIgnore
private SomeType myfield;
...
// getters & setters
}
Is it possible to configure ObjectWriter so that it includes myfield during serialization even though being ingored?
Rationale: MyClass is serialized in many places and only in single specific one I want to have myfield.
It is possible to configure ObjectMapper to disable a JsonIgnore function. Following are some possible solution you can try with:
1.
Disable JsonIgnore function for a particular annotated field.
You can create a custom JsonIgnore annotation and a custom JacksonAnnotationIntrospector to remove the annotation from mapper context.
Following are the ideas:
Annotate #MyJsonIgnore to the fields that should be ignored while serialization:
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class MyClass {
#MyJsonIgnore
private SomeType myField;
}
#MyJsonIgnore is a simple custom annotation that wrap #JsonIgnore:
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotationsInside
#JsonIgnore
public #interface MyJsonIgnore {
}
A custom JacksonAnnotationIntrospector is implemented to remove #MyJsonIgnore from mapper context:
public class DisablingMyJsonIgnoreIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean isAnnotationBundle(final Annotation ann) {
if (ann.annotationType().equals(MyJsonIgnore.class)) {
return false;
} else {
return super.isAnnotationBundle(ann);
}
}
After that, you can set the introspector on a ObjectMapper during configuration:
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new DisablingMyJsonIgnoreIntrospector());
It results that the fields annotated with #MyJsonIgnore can be marshaled properly.
2.
Disable JsonIgnore function for the mapper
Your can create a custom JacksonAnnotationIntrospector and override hasIgnoreMarker method to always return false:
public static class DisablingJsonIgnoreIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return false;
}
}
hasIgnoreMarker is to check whether there is annotation to ignore json property. Return false will disable the JsonIngore function.
3.
Disable all annotations and specify what kinds of properties are auto-detected for a given ObjectMapper:
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
This simply disable all annotations.
Hope this can help.
One more option is to use the AnnotationIntrospector.nopInstance() if you want to avoid all Jackson's annotations in your pojo including #JsonIgnore e.g.
JsonMapper.builder().annotationIntrospector(AnnotationIntrospector.nopInstance()).build()...
or
new ObjectMapper().setAnnotationIntrospector(AnnotationIntrospector.nopInstance())...
I'm trying to serialize an object in Java using Jackson, but when I'm trying to serialize it, it gives me this error:
No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer
I tried this post, but it didn't help.
Here is the class I'm trying to serialize:
public class Repository {
public String name;
#JsonIgnore // to avoid recursive calls
public ArrayList<UserRole> contributors = new ArrayList<UserRole>();
public User self;
public ArrayList<FileInfo> files;
public RepositoryType repositoryType;
public String path;
}
I also tried to create getters/setters for each field but still nothing.
Here is my serialization method:
public static String convertObjectToJson(Object object) throws IOException {
ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = objectWriter.writeValueAsString(object); //error on this line
return json;
}
Looks like your one of your classes has java.io.FileDescriptor reference.
By default, Jackson will only work with with fields that are either public, or have a public getter methods – serializing an entity that has all fields private or package private will fail
If you look at the source code of java.io.FileDescriptor you can see
there are private fields without public getters.
You should configure your objectMapper visibility to allow access to private fields also.
// For jackson 2.*
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
// For jackson lower than 2
objectMapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);
I was facing problems to send objects to Thymeleaf template with ResponseEntity it was giving me exception "StackOverFlowError" while serializing and your note " #JsonIgnore // to avoid recursive calls" solved my problem. Thanks
i'm using Jersey to build a REST service and as Json Processor i set Jackson in my application.
#javax.ws.rs.ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("controller");
register(JacksonFeature.class);
}
I implement a ContextResolver for Jacksons ObjectMapper (as it's suggested in this post Configure Jersey/Jackson to NOT use #XmlElement field annotation for JSON field naming) which creates an ObjectMapper that doesn't fail on unknown properties during deserialization:
#Provider
public class MyJsonObjectMapperProvider implements ContextResolver<ObjectMapper> {
#Override
public ObjectMapper getContext(Class<?> type)
{
System.out.println("mapper!!!");
ObjectMapper result = new ObjectMapper();
result.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return result;
}
}
and then i register this class in my application inserting register(MyJsonObjectMapperProvider.class) in the class MyApplication shown above. I obtain what i want, in sense that if there are unknown properties in the json the object mapper doesn't fail.
My problem is another; i have this class that i use to map a specified Json, in order to deserialize it and subsequently serialize it:
public class Version {
private String status;
private String updated;
private String id;
private List<Link> links;
#XmlElement(name = "media-types")
private List<MediaTypes> media_types;
//constructor + getter and setter
}
The problem is about the element media_types and the use of the annotation #XmlElement. Before i insert the ContextResolver to personalize ObjectMapper all works fine, in fact after serialization i obtain a json in which the element/attribute media_types has as name media-types; on the contrary with ContextResolver this element doesn't change it's name and has media_types. I think that, during serialization, the annotation XmlElement doesn't work, but i'm not sure that this is the correct reason.
Another attempt i try to do is to put #JsonProperty("media-types") annotation instead of #XmlElement annotation but with no result; in fact with this annotation i obtain also a Processing Exception.
The last attempt (in addition to what has been suggested by the previous post) was that of insert these lines of code in the ContextResolver:
AnnotationIntrospector intr = new AnnotationIntrospector.Pair(new JaxbAnnotationIntrospector(),new JacksonAnnotationIntrospector());
// usually we use same introspector(s) for both serialization and deserialization:
result.getDeserializationConfig().withAnnotationIntrospector(intr);
result.getSerializationConfig().withAnnotationIntrospector(intr);
in order to use both JaxbAnnotation and JacksonAnnotation but the name of the field in question remain media_types.
I hope i was clear in explain my problem and thanks you in advance for your help!
I need to configure Jackson in a specific way which I'll describe below.
Requirements
Annotated fields are serialized with only their id:
If the field is a normal object, serialize its id
If the field is a collection of objects, serialize an array of id
Annotated fields get their property names serialized differently:
If the field is a normal object, add "_id" suffix to property name
If the field is a collection of objects, add "_ids" suffix to property name
For the annotation I was thinking something like a custom #JsonId, ideally with an optional value to override the name just like #JsonProperty does
The id property should be defined by the user, either using:
The already existing Jackson's #JsonIdentityInfo
Or by creating another class or field annotation
Or by deciding which annotation to inspect for id property discoverability (useful for JPA scenarios, for example)
Objects should be serialized with a wrapped root value
Camel case naming should be converted to lower case with underscores
All of this should be deserializable (by constructing an instance with just the id setted)
An example
Considering these POJO's:
//Inform Jackson which property is the id
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public abstract class BaseResource{
protected Long id;
//getters and setters
}
public class Resource extends BaseResource{
private String name;
#JsonId
private SubResource subResource;
#JsonId
private List<SubResource> subResources;
//getters and setters
}
public class SubResource extends BaseResource{
private String value;
//getters and setters
}
A possible serialization of a Resource instance could be:
{
"resource":{
"id": 1,
"name": "bla",
"sub_resource_id": 2,
"sub_resource_ids": [
1,
2,
3
]
}
}
So far...
Requirement #5 can be accomplished by configuring ObjectMapper in the following way:
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
And then using #JsonRootName("example_root_name_here") in my POJO's.
Requirement #6 can be accomplished by configuring ObjectMapper in the following way:
objectMapper.setPropertyNamingStrategy(
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
As you can see there are still lots of requirements to fulfill. For those wondering why I need such a configuration, it's because I'm developing a REST webservice for ember.js (more specifically Ember Data).
You would appreciate very much if you could help with any of the requirements.
Thanks!
Most (all?) of your requirements can be accomplished through the use of a contextual serializer. Taking one answer from ContextualDeserializer for mapping JSON to different types of maps with Jackson and Jackson's wiki (http://wiki.fasterxml.com/JacksonFeatureContextualHandlers) I was able to come up with the following.
You need to start with the #JsonId annotation, which is the key indicating a property needs to only use the Id property.
import com.fasterxml.jackson.annotation.*;
import java.lang.annotation.*;
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotation // important so that it will get included!
public #interface JsonId {
}
Next is the actual ContextualSerializer, which does the heavy lifting.
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.core.*;
import java.io.*;
public class ContextualJsonIdSerializer
extends JsonSerializer<BaseResource>
implements ContextualSerializer/*<BaseResource>*/
{
private ObjectMapper mapper;
private boolean useJsonId;
public ContextualJsonIdSerializer(ObjectMapper mapper) { this(mapper, false); }
public ContextualJsonIdSerializer(ObjectMapper mapper, boolean useJsonId) {
this.mapper = mapper;
this.useJsonId = useJsonId;
}
#Override
public void serialize(BaseResource br, JsonGenerator jgen, SerializerProvider provider) throws IOException
{
if ( useJsonId ) {
jgen.writeString(br.getId().toString());
} else {
mapper.writeValue(jgen, br);
}
}
#Override
public JsonSerializer<BaseResource> createContextual(SerializerProvider config, BeanProperty property)
throws JsonMappingException
{
// First find annotation used for getter or field:
System.out.println("Finding annotations for "+property);
if ( null == property ) {
return new ContextualJsonIdSerializer(mapper, false);
}
JsonId ann = property.getAnnotation(JsonId.class);
if (ann == null) { // but if missing, default one from class
ann = property.getContextAnnotation(JsonId.class);
}
if (ann == null ) {//|| ann.length() == 0) {
return this;//new ContextualJsonIdSerializer(false);
}
return new ContextualJsonIdSerializer(mapper, true);
}
}
This class looks at BaseResource properties and inspects them to see if the #JsonId annotation is present. If it is then only the Id property is used, otherwise a passed in ObjectMapper is used to serialize the value. This is important because if you try to use the mapper that is (basically) in the context of the ContextualSerializer then you will get a stack overflow since it will eventually call these methods over and over.
You're resource should look something like the following. I used the #JsonProperty annotation instead of wrapping the functionality in the ContextualSerializer because it seemed silly to reinvent the wheel.
import java.util.*;
import com.fasterxml.jackson.annotation.*;
public class Resource extends BaseResource{
private String name;
#JsonProperty("sub_resource_id")
#JsonId
private SubResource subResource;
#JsonProperty("sub_resource_ids")
#JsonId
private List<SubResource> subResources;
//getters and setters
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public SubResource getSubResource() {return subResource;}
public void setSubResource(SubResource subResource) {this.subResource = subResource;}
public List<SubResource> getSubResources() {return subResources;}
public void setSubResources(List<SubResource> subResources) {this.subResources = subResources;}
}
Finally the method that performs the serialization just creates an additional ObjectMapper and registers a module in the original ObjectMapper.
// Create the original ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
// Create a clone of the original ObjectMapper
ObjectMapper objectMapper2 = new ObjectMapper();
objectMapper2.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
objectMapper2.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper2.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
// Create a module that references the Contextual Serializer
SimpleModule module = new SimpleModule("JsonId", new Version(1, 0, 0, null));
// All references to SubResource should be run through this serializer
module.addSerializer(SubResource.class, new ContextualJsonIdSerializer(objectMapper2));
objectMapper.registerModule(module);
// Now just use the original objectMapper to serialize
I'd just like to create the Jackson mapping equivalent of the below :
{\"isDone\": true}
I think I need to create a class like this :
public class Status {
private boolean isDone;
public boolean isDone{
return this.isDone;
}
public void setDone(boolean isDone){
this.isDone = isDone;
}
}
But how do I instatiate it and then write the JSON to a string ?
A problem with your example and Jackson is the default choices of JSON property names: Jackson will see isDone and setDone and choose done as the JSON property name. You can override this default choice using the JsonProperty annotation:
public class Status
{
private boolean isDone;
#JsonProperty("isDone")
public boolean isDone()
{
return this.isDone;
}
#JsonProperty("isDone")
public void setDone(boolean isDone)
{
this.isDone = isDone;
}
}
Then:
Status instance = new Status();
String jsonString = null;
instance.setDone(true);
ObjectMapper mapper = new ObjectMapper();
jsonString = mapper.writeValueAsString(instance);
Now jsonString contains { "isDone" : true }. Note that you can also write the string to an OutputStream using ObjectMapper.writeValue(OutputStream, Object), or to a Writer using ObjectMapper.writeValue(Writer, Object).
In this case you really only need the JsonProperty annotation on either of your accessors, but not both. Just annotating isDone will get you the JSON property name that you want.
An alternative to using the JsonProperty annotation is to rename your accessors setIsDone/getIsDone. Then the annotations are unnecessary.
See the quick and dirty Jackson tutorial: Jackson in 5 minutes. Understanding of the specific properties came from looking through the docs for Jackson annotations.
Right. The code needed:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new Status()));