How to serialize boolean to JSON as strings using Jackson - json

We have developed a REST service using Jersey JAX-RS and Jackson (version 2.1.5) for JSON serialization.
As the application is supposed to be a drop-in replacement for the older legacy service acting as a backend to an existing mobile app, we need to do some tweaking to the way Jackson serializes boolean values.
Existing mobile app expects boolean values to be expressed as strings of "true" and "false" like this:
{"Foo":"true","Bar":"false"}
So I have searched for a way to influence the Jackson serialization to output booleans as strings, but I have no success.
Oh, and btw - since our model classes have been generated from xml schemas using JAXB class generation, we can not annotate the classes with json annotations.
I have tried to register a module with ObjectMapper, that provides a customized serializer for boolean objects, but it did not seem to work.

Jackson 2.16 Custom Serializer for primitive data type .
you should write your own serializer. example code for boolean data type
// create a module with a custom Boolean serializer
class BooleanSerializer extends JsonSerializer<Boolean> {
private final static Logger logger = LoggerFactory.getLogger(BooleanSerializer.class);
#Override
public void serialize(Boolean value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
logger.info("serializing boolean value as a Strng {}",value);
jgen.writeString(value.toString());
}
}
//register custom BooleanSerializer class with ObjectMapper.
// Here's where we configure the object mapper
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("BooleanAsString", new Version(1, 0, 0, null, null, null));
simpleModule.addSerializer(Boolean.class,new BooleanSerializer());
simpleModule.addSerializer(boolean.class,new BooleanSerializer());
mapper.registerModule(module);

Okay, it seems that either my IDE or Maven was acting up and refused to build or reference the changes I made in my ObjectMapper configuration.
For the sake of the future visitors, here is the gist of the solution to the issue of making Jackson data binding to spit out boolean values as strings:
In my customized ObjectMapper context resolver, I just had to add special serializer for boolean object types:
// create a module with a custom Boolean serializer
SimpleModule module = new SimpleModule("BooleanAsString", new Version(1, 0, 0, null, null, null));
module.addSerializer(new NonTypedScalarSerializerBase<Boolean>(Boolean.class){
#Override
public void serialize(Boolean value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
ObjectMapperProvider.log.debug("serializing boolean value as a Strng");
jgen.writeString(value.toString());
}
});
// Here's where we configure the object mapper
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
That's it. If you know how to configure your ObjectMapper, then this should be enough to get you going.

Since version 2.8, just make this:
ObjectMapper mapper = new ObjectMapper()
mapper.configOverride(Boolean.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING))
mapper.configOverride(boolean.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING))

Related

How to simulate a CDI #Produces annotation on a JUnit

I am writing a JUnit test for a class which does something like:
org.glassfish.jersey.client.JerseyClient client = getHTTPClient(SSLContextFactory.getContext(), connectTimeout, readTimeout, true);
client.register(CustomJAXBContextProvider.class); // subclass of javax.ws.rs.ext.ContextResolver<JAXBContext>
client.property(MarshallerProperties.JSON_INCLUDE_ROOT, true);
WebTarget webTarget = client.target(contextPath);
Response response = webTarget.request(MediaType.APPLICATION_JSON.get()
return response.readEntity(ResponseModel.class);
The application runs inside a WebLogic container and has another class with a CDI #Produces annotation:
public class ObjectMapperProvider {
private ObjectMapper objectMapper;
#Produces
public ObjectMapper objectMapper() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new JSR310Module());
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
return objectMapper;
}
}
When I run the JUnit test from outside WebLogic I get an error
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "fieldName" (class ResponseModel), not marked as
ignorable
Because the JSON response contains a field which is not declared in the model and the JUnit is not obtaining the ObjectMapper through the #Produces annotation but getting a default one. The JAXBContext is EclipseLink MOXy.
My question is: How do I get the code tested by my JUint to instantiate ObjectMapper as returned from ObjectMapperProvider instead of a default one lacking the DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false?
We cover this exact scenario using Mockito. Depending on how JaxBContext is created, you could use a spy to return a mock. Without posting your complete test code and the class under test, it's hard to give a more complete answer than that.

How can I define float/double numbers precision in json from Spring MVC?

How can I set Spring MVC to serialize float or double numbers to json with a limited number of decimals?
If you are serializing from bean, the easiset would be to write a custom deserializer, e.g.
public class FloatSerializer extends JsonSerializer<Float> {
#Override
public void serialize(Float value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (null == value) {
jgen.writeNull();
} else {
final String serializedValue = null;
// do your customization here
jgen.writeNumber(serializedValue);
}
}
}
and apply it to the field, e.g.
#JsonSerialize(using = FloatSerializer.class)
public Float getFloatField()
or simply convert the value in the setter of the property if its a one time conversion that works for you
-- Update with respect to the comment
If you want to apply globally than you'll have to use a custom jackson object mapper in your spring mvc and follow the guide for adding modules http://wiki.fasterxml.com/JacksonFeatureModules, the gist is along the following lines
ObjectMapper mapper = new ObjectMapper();
// basic module metadata just includes name and version (both for troubleshooting; but name needs to be unique)
SimpleModule module = new SimpleModule("EnhancedDatesModule", new Version(0, 1, 0, "alpha"));
// functionality includes ability to register serializers, deserializers, add mix-in annotations etc:
module.addSerializer(MyBean.class, new MyCustomSerializer());
module.addDeserializer(MyBean.class, new MyCustomSerializer());
// and the magic happens here when we register module with mapper:
mapper.registerModule(module);

Jackson serialization and lazy loading in Spring MVC

I'm trying to serialize an object with several lazily loaded properties, and I'm getting the following error:
Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
After some searching I have tried this in my #Configuration class, but it doesn't seem to help:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
Hibernate4Module hibernateModule = new Hibernate4Module();
hibernateModule.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
objectMapper.registerModule(hibernateModule);
return objectMapper;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
When I change to FetchType.EAGER the application works fine.
The problem is related to the fact that related objects to the main one are not really loaded when you execute the query and not use the FetchType.EAGER; by using the FetchType.EAGER you tell hibernate: load the main entity and all the related entities; this can have not too much sense (you can risk to load all the database in one query)
Returning to jackson marshaller, when objects are "proxied" it is not able in serializing them
IMHO i'd do the following:
i'd create a DTO object to be serialized (I'd not serialize the Hibernate object)
i'd put in this DTO only the needed properties and data
if user need to see related objects a specific call would be executed and data related to the selected object will be loaded from DB and serialized (in specific DTO objects)

Jackson: is it possible to replace the serializer set with #JsonSerialize annotation (e.g. with ObjectMapper)?

Quick question: is it possible to override #JsonSerialize annotation (using attribute) with ObjectMapper?
I'm have spring-security-oauth2 integrated and I want to customize the way OAuth2Exception is serialized to JSON format. The problem is that this class uses
#JsonSerialize(using = OAuth2ExceptionJackson2Serializer.class)
I tried registering custom serializer with:
SimpleModule module = new SimpleModule()
module.addSerializer(OAuth2Exception, new JsonSerializer<OAuth2Exception>() {
#Override
void serialize(OAuth2Exception value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString('{"test":"test"}')
}
})
ObjectMapper objectMapper = new ObjectMapper()
objectMapper.registerModule(module)
but it didn't work - the serializer set with #JsonSerialize is used instead of the custom one.
Is there any other way to replace the serializer set with #JsonSerialize?
PS: the sample code is written in groovy
For such case Jackson has a mechanism called mix-in annotations.
You can create a class that overrides initial annotations.
#JsonSerialize(using=MySerializer.class)
public static abstract class OAuth2ExceptionMixIn {
}
Then register it in the object mapper:
objectMapper.addMixIn(OAuth2Exception.class, OAuth2ExceptionMixIn.class);
And that's it. Now Jackson should use your MySerializer instead of the initial OAuth2ExceptionJackson2Serializer
.

How to write custom serializer and deserializer in Jackson?

I have a class that has more than a dozen properties. For most of the properties of primitive type, I hope to use the default BeanSerializer and BeanDeserializer or whatever to reduce the cumbersome code I need to write. For other properties of custom and array types, I want to do some custom serializer/deserializer. Note that I am not able to change the underlying JSON string. But I have full access to the android code. I am using Jackson 1.7.9/Ektorp 1.1.1.
shall I subclass BeanDeserializer? I am having trouble with that. It expects a default constructor with no parameters but I don't know how to call the super constructor.
class MyType{
// a dozen properties with primitive types String, Int, BigDecimal
public Stirng getName();
public void setName(String name);
// properties that require custom deserializer/serializer
public CustomType getCustom();
public void setCustom(CustomType ct);
}
class MyDeserializer extends BeanDeserialzer{
// an exception is throw if I don't have default constructor.
// But BeanDeserializer doesn't have a default constructor
// It has the below constructor that I don't know how to fill in the parameters
public MyDeserializer(AnnotatedClass forClass, JavaType type,
BeanProperty property, CreatorContainer creators,
BeanPropertyMap properties,
Map<String, SettableBeanProperty> backRefs,
HashSet<String> ignorableProps, boolean ignoreAllUnknown,
SettableAnyProperty anySetter) {
super(forClass, type, property, creators, properties, backRefs, ignorableProps,
ignoreAllUnknown, anySetter);
}
#Override
public Object deserialize(JsonParser jp, DeserializationContext dc, Object bean)
throws IOException, JsonProcessingException {
super.deserialize(jp, dc, bean);
MyType c = (MyType)bean;
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(jp, JsonNode.class);
// Use tree model to construct custom
// Is it inefficient because it needs a second pass to the JSON string to construct the tree?
c.setCustom(custom);
return c;
}
}
I searched Google but couldn't find any helpful examples/tutorial. If anyone can send me some working examples that would be great! Thanks!
To sub-class BeanSerializer/-Deserializer, you would be better off using a more recent version of Jackson, since this area has been improved with explicit support via BeanSerializerModifier and BeanDeserializerModifier, which can alter configuration of instances.
But just to make sure, you can also specify custom serializer/deserializer to just be used on individual properties, like so:
class Foo {
#JsonSerialize(using=MySerializer.class)
public OddType getValue();
}