Play Java validation fail for Set and Map - java

I use Play 2.5.12 to provide a web service to create an object and validate its attributes. Here is a simplified code of what I want to do:
public class Example {
private String lastName;
private List<String> firstNames;
private Map<String, Integer> vehicles;
public Example() {}
public String validate() {
if (vehicles.get("Ferrari") != null)
return "Liar!";
return null;
}
#Override
public String toString() {
return new ToStringBuilder(this).append(lastName).append(firstNames).append(vehicles).toString();
}
// getters and setters
}
public class ExampleController extends Controller {
private FormFactory formFactory;
#Inject
public ExampleController(FormFactory formFactory) {
this.formFactory = formFactory;
}
#BodyParser.Of(BodyParser.Json.class)
public Result createExample() {
Example exampleFromJackson = Json.fromJson(request().body().asJson(), Example.class);
System.out.println(exampleFromJackson.toString());
Example exampleFromForm = formFactory.form(Example.class).bindFromRequest().get();
System.out.println(exampleFromForm.toString());
// etc
return created();
}
}
If I call the web service with a body like this:
{
"lastName": "Martin",
"firstNames": ["Robert", "Cecil"],
"vehicles": {
"BMW": 1,
"Seat": 1
}
}
The deserialized object by jackson prints correctly then this error occurs:
org.springframework.beans.InvalidPropertyException: Invalid property 'firstNames[0]' of bean class [models.Example]: Property referenced in indexed property path 'firstNames[0]' is neither an array nor a List nor a Map; returned value was [[]]
If I replace the Set by a List, I can avoid this error and then I obtain the following:
models.Example#68d2162a[Martin,[Robert, Cecil],{BMW=1, Seat=1}]
models.Example#29ef1c11[Martin,[Robert, Cecil],{}]
The deserialized object by jackson is correct but the one obtained by the request isn't so I can't do a correct validation.
So my questions are:
- Why Play doesn't let me use a Set?
- Why is the Map not retrieved?

Related

Jackson: How to edit existing property to the JSON without modifying the POJO?

I need to edit the name of "existing field" in POJO instead of adding "extra_field". Is it possible with the approach referenced link below?
Please note I do not want to use #JsonProperty annotation.
Requirement is, I have a POJO and want to use different field name every time without change in POJO. For example I have a field c_id in POJO and some times it need to write as cust_id and another time it would be my_id.
Also note I cannot change implementation of POJO as it is already used in several modules and have generic implementation.
POJO Example:
class MyPojo {
String id;
// getter and setters
}
Expected output can be the following: (name of field can be changed)
{"cust_id": "123"}
{"my_id": "123"}
Mixins
The easiest way to modify the output of Jackson without adding annotations to the original POJO is using mixins.
Just define a mixin-class with the necessary annotations and indicate to Jackson that you want to use the mixin when serializing the original object.
private static class MyPojoMixin {
#JsonProperty("cust_id")
private String id;
}
public String serializeWithMixin(MyPojo p) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(MyPojo.class, MyPojoMixin.class);
return mapper.writeValueAsString(p);
}
Custom property naming strategy
If you need to programmatically change the field-name, you might not be able to use the mixin solution. You could then use a custom PropertyNamingStrategy:
public class IdRenamingStrategy extends PropertyNamingStrategy {
private final PropertyNamingStrategy inner;
private final String newIdPropertyName;
public IdRenamingStrategy(String newIdPropertyName) {
this(PropertyNamingStrategy.LOWER_CAMEL_CASE, newIdPropertyName);
}
public IdRenamingStrategy(PropertyNamingStrategy inner, String newIdPropertyName) {
this.inner = inner;
this.newIdPropertyName = newIdPropertyName;
}
private String translate(String propertyName) {
if ("id".equals(propertyName)) {
return newIdPropertyName;
} else {
return propertyName;
}
}
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return inner.nameForField(config, field, translate(defaultName));
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return inner.nameForGetterMethod(config, method, translate(defaultName));
}
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return inner.nameForSetterMethod(config, method, translate(defaultName));
}
#Override
public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) {
return inner.nameForConstructorParameter(config, ctorParam, translate(defaultName));
}
}
This can be used like this:
public String serializeWithPropertyNamingStrategy(MyPojo p) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new IdRenamingStrategy("cust_id"));
return mapper.writeValueAsString(p));
}

How to mock array of class using Mockito

I want to mock Order array class Order[].class. below mockMapper reads Order[].class and need to return Order[].class.
Service class
public class OrdersConnectorImpl {
public Order getOrderById(String Id, OrderType orderType) throws Exception {
Response response = null;
response = orderServiceTarget.queryParam("ID", Id).queryParam(ORDER_TYPE, orderType).request().accept(MediaType.APPLICATION_JSON)
.get();
final StatusType responseStatus = response.getStatusInfo();
final String serverResponseStr = response.readEntity(String.class);
if (responseStatus.equals(Response.Status.OK)) {
objectMapper = getObjectMapper(); // we have a private method in this class
Order[] orders = objectMapper.readValue(serverResponseStr, Order[].class);
if(orders.length>0) {
return orders[0];
}
}
}
}
Test class
public class OrdersConnectorImplTest {
private ObjectMapper mockMapper;
private class MockOrdersConnectorImpl extends OrdersConnectorImpl {
#Override
protected ObjectMapper getObjectMapper() {
return mockMapper;
}
}
}
#Test
public void test_getRenewalOrderForContract() throws Exception {
Response mockResponse = mock(javax.ws.rs.core.Response.class);
Order mockOrder = mock(Order.class);
when(mockResponse.getStatusInfo()).thenReturn(Status.OK);
when(mockResponse.readEntity(String.class)).thenReturn("{}");
when(mockBuilder.get()).thenReturn(mockResponse);
when(mockMapper.readValue("{}", Order[].class)).thenReturn(mockOrder); // this is the problem line
orderConnector.getOrderById("id", OrderType.NEW);
}
}
Please correct me here how to return expected.
You have autowired mockMapper which means, the actual object of ObjectMapper will be injected.
And in the when part, you setting up the behavior of mockMapper, which shouldn't be the case.
Edit 1
In your case, there is no need for mocking the Order class, you have to return the array Order which you can create in the tests.
For your information, with Junit there is no way, you can mock the object which is been created inside the method.

Setting default values to null fields when mapping with Jackson

I am trying to map some JSON objects to Java objects with Jackson. Some of the fields in the JSON object are mandatory(which I can mark with #NotNull) and some are optional.
After the mapping with Jackson, all the fields that are not set in the JSON object will have a null value in Java. Is there a similar annotation to #NotNull that can tell Jackson to set a default value to a Java class member, in case it is null?
Edit:
To make the question more clear here is some code example.
The Java object:
class JavaObject {
#NotNull
public String notNullMember;
#DefaultValue("Value")
public String optionalMember;
}
The JSON object can be either:
{
"notNullMember" : "notNull"
}
or:
{
"notNullMember" : "notNull",
"optionalMember" : "optional"
}
The #DefaultValue annotations is just to show what I am asking. It's not a real annotation. If the JSON object is like in the first example I want the value of the optionalMember to be "Value" and not null. Is there an annotation that does such a thing?
There is no annotation to set default value.
You can set default value only on java class level:
public class JavaObject
{
public String notNullMember;
public String optionalMember = "Value";
}
Only one proposed solution keeps the default-value when some-value:null was set explicitly (POJO readability is lost there and it's clumsy)
Here's how one can keep the default-value and never set it to null
#JsonProperty("some-value")
public String someValue = "default-value";
#JsonSetter("some-value")
public void setSomeValue(String s) {
if (s != null) {
someValue = s;
}
}
Use the JsonSetter annotation with the value Nulls.SKIP
If you want to assign a default value to any param which is not set in json request then you can simply assign that in the POJO itself.
If you don't use #JsonSetter(nulls = Nulls.SKIP) then the default value will be initialised only if there is no value coming in JSON, but if someone explicitly put a null then it can lead to a problem. Using #JsonSetter(nulls = Nulls.SKIP) will tell the Json de-searilizer to avoid null initialisation.
Value that indicates that an input null value should be skipped and the default assignment is to be made; this usually means that the property will have its default value.
as follow:
public class User {
#JsonSetter(nulls = Nulls.SKIP)
private Integer Score = 1000;
...
}
You can create your own JsonDeserializer and annotate that property with #JsonDeserialize(using = DefaultZero.class)
For example: To configure BigDecimal to default to ZERO:
public static class DefaultZero extends JsonDeserializer<BigDecimal> {
private final JsonDeserializer<BigDecimal> delegate;
public DefaultZero(JsonDeserializer<BigDecimal> delegate) {
this.delegate = delegate;
}
#Override
public BigDecimal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return jsonParser.getDecimalValue();
}
#Override
public BigDecimal getNullValue(DeserializationContext ctxt) throws JsonMappingException {
return BigDecimal.ZERO;
}
}
And usage:
class Sth {
#JsonDeserialize(using = DefaultZero.class)
BigDecimal property;
}
There is a solution, if you use Lombok's Builder annotation, you can combine Lombok with Jackson via the #Jacksonized annotation.
Without this, the combination of Lombok and Jackson is not working for this.
Via adding the #Builder.Default on the property you are then able to set default values.
#Value
#Builder
#Jacksonized
public class SomeClass {
String field1;
#Builder.Default
String field2 = "default-value";
}
So, in the incoming json request, if the field2 is not specified, then the Builder.default annotation will allow the Builder interface to set the specified default-value into the property, if not, the original value from the request is set into that.
Looks like the solution is to set the value of the properties inside the default constructor. So in this case the java class is:
class JavaObject {
public JavaObject() {
optionalMember = "Value";
}
#NotNull
public String notNullMember;
public String optionalMember;
}
After the mapping with Jackson, if the optionalMember is missing from the JSON its value in the Java class is "Value".
However, I am still interested to know if there is a solution with annotations and without the default constructor.
Make the member private and add a setter/getter pair.
In your setter, if null, then set default value instead.
Additionally, I have shown the snippet with the getter also returning a default when internal value is null.
class JavaObject {
private static final String DEFAULT="Default Value";
public JavaObject() {
}
#NotNull
private String notNullMember;
public void setNotNullMember(String value){
if (value==null) { notNullMember=DEFAULT; return; }
notNullMember=value;
return;
}
public String getNotNullMember(){
if (notNullMember==null) { return DEFAULT;}
return notNullMember;
}
public String optionalMember;
}
Another option is to use InjectableValues and #JacksonInject. It is very useful if you need to use not always the same value but one get from DB or somewhere else for the specific case. Here is an example of using JacksonInject:
protected static class Some {
private final String field1;
private final String field2;
public Some(#JsonProperty("field1") final String field1,
#JsonProperty("field2") #JacksonInject(value = "defaultValueForField2",
useInput = OptBoolean.TRUE) final String field2) {
this.field1 = requireNonNull(field1);
this.field2 = requireNonNull(field2);
}
public String getField1() {
return field1;
}
public String getField2() {
return field2;
}
}
#Test
public void testReadValueInjectables() throws JsonParseException, JsonMappingException, IOException {
final ObjectMapper mapper = new ObjectMapper();
final InjectableValues injectableValues =
new InjectableValues.Std().addValue("defaultValueForField2", "somedefaultValue");
mapper.setInjectableValues(injectableValues);
final Some actualValueMissing = mapper.readValue("{\"field1\": \"field1value\"}", Some.class);
assertEquals(actualValueMissing.getField1(), "field1value");
assertEquals(actualValueMissing.getField2(), "somedefaultValue");
final Some actualValuePresent =
mapper.readValue("{\"field1\": \"field1value\", \"field2\": \"field2value\"}", Some.class);
assertEquals(actualValuePresent.getField1(), "field1value");
assertEquals(actualValuePresent.getField2(), "field2value");
}
Keep in mind that if you are using constructor to create the entity (this usually happens when you use #Value or #AllArgsConstructor in lombok ) and you put #JacksonInject not to the constructor but to the property it will not work as expected - value of the injected field will always override value in json, no matter whether you put useInput = OptBoolean.TRUE in #JacksonInject. This is because jackson injects those properties after constructor is called (even if the property is final) - field is set to the correct value in constructor but then it is overrided (check: https://github.com/FasterXML/jackson-databind/issues/2678 and https://github.com/rzwitserloot/lombok/issues/1528#issuecomment-607725333 for more information), this test is unfortunately passing:
protected static class Some {
private final String field1;
#JacksonInject(value = "defaultValueForField2", useInput = OptBoolean.TRUE)
private final String field2;
public Some(#JsonProperty("field1") final String field1,
#JsonProperty("field2") #JacksonInject(value = "defaultValueForField2",
useInput = OptBoolean.TRUE) final String field2) {
this.field1 = requireNonNull(field1);
this.field2 = requireNonNull(field2);
}
public String getField1() {
return field1;
}
public String getField2() {
return field2;
}
}
#Test
public void testReadValueInjectablesIncorrectBehavior() throws JsonParseException, JsonMappingException, IOException {
final ObjectMapper mapper = new ObjectMapper();
final InjectableValues injectableValues =
new InjectableValues.Std().addValue("defaultValueForField2", "somedefaultValue");
mapper.setInjectableValues(injectableValues);
final Some actualValueMissing = mapper.readValue("{\"field1\": \"field1value\"}", Some.class);
assertEquals(actualValueMissing.getField1(), "field1value");
assertEquals(actualValueMissing.getField2(), "somedefaultValue");
final Some actualValuePresent =
mapper.readValue("{\"field1\": \"field1value\", \"field2\": \"field2value\"}", Some.class);
assertEquals(actualValuePresent.getField1(), "field1value");
// unfortunately "field2value" is overrided because of putting "#JacksonInject" to the field
assertEquals(actualValuePresent.getField2(), "somedefaultValue");
}
Another approach is to use JsonDeserializer, e.g.:
public class DefaultValueDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
return jsonParser.getText();
}
#Override
public String getNullValue(DeserializationContext ctxt) {
return "some random value that can be different each time: " + UUID.randomUUID().toString();
}
}
and then annotate a field like that:
public class Content {
#JsonDeserialize(using = DefaultValueDeserializer.class)
private String someField;
...
}
keep in mind that you can use attributes in getNullValue(DeserializationContext ctxt) passed using
mapper.reader().forType(SomeType.class).withAttributes(singletonMap("dbConnection", dbConnection)).readValue(jsonString);
like that:
#Override
public String getNullValue(DeserializationContext ctxt) {
return ((DbConnection)ctxt.getAttribute("dbConnection")).getDefaultValue(...);
}
Hope this helps to someone with a similar problem.
P.S. I'm using jackson v. 2.9.6
I had a similar problem, but in my case the default value was in database. Below is the solution for that:
#Configuration
public class AppConfiguration {
#Autowired
private AppConfigDao appConfigDao;
#Bean
public Jackson2ObjectMapperBuilder builder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.deserializerByType(SomeDto.class,
new SomeDtoJsonDeserializer(appConfigDao.findDefaultValue()));
return builder;
}
Then in SomeDtoJsonDeserializer use ObjectMapper to deserialize the json and set default value if your field/object is null.
There are already a lot of good suggestions, but here's one more. You can use #JsonDeserialize to perform an arbitrary "sanitizer" which Jackson will invoke post-deserialization:
#JsonDeserialize(converter=Message1._Sanitizer.class)
public class Message1 extends MessageBase
{
public String string1 = "";
public int integer1;
public static class _Sanitizer extends StdConverter<Message1,Message1> {
#Override
public Message1 convert(Message1 message) {
if (message.string1 == null) message.string1 = "";
return message;
}
}
}
You can also apply #JsonInclude(Include.NON_NULL) to the entire class using Jackson > 2. This will ignore null fields.
Value that indicates that only properties with non-null values are to be included.
#JsonInclude(Include.NON_NULL)
class Foo
{
String bar;
}
https://stackoverflow.com/a/11761975/5806870

Change Json key name dynamically - Jackson

I have a java class like :
class TestJsonClass {
private String propertyA;
private String propertyB;
private String propertyC;
}
Now during runtime i want to give different property names for each of the property, and not a static one using #JsonProperty("sample")
How do I accomplish this? I am using Jackson library ad Spring MVC
Thanks in advance...
You can make use of Modules for this purpose. This is the easiest solutions to your problem. Here is an example:
A simple class that can carry your property-name-mappings for each request:
public class PropertyNameMapper {
// The class for which the mappings need to take place.
public Class<?> classToFilter;
// The mappings property names. Key would be the existing property name
// value would be name you want in the ouput.
public Map<String, String> nameMappings = Collections.emptyMap();
public PropertyNameMapper(Class<?> classToFilter, Map<String, String> nameMappings) {
this.classToFilter = classToFilter;
this.nameMappings = nameMappings;
}
}
A custom BeanPropertyWriter that will be used for specifying the output name for the properties.
public class MyBeanPropertyWriter extends BeanPropertyWriter {
// We would just use the copy-constructor rather than modifying the
// protected properties. This is more in line with the current design
// of the BeanSerializerModifier class (according to its documentation).
protected MyBeanPropertyWriter(BeanPropertyWriter base, String targetName) {
super(base, new SerializedString(targetName));
}
}
Now, a custom BeanSerializerModifier that is called each time to allow you to modify the serialized properties.
public class MySerializerModifier extends BeanSerializerModifier {
public List<BeanPropertyWriter> changeProperties(
SerializationConfig config, BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
List<PropertyNameMapper> propertyMappings = getNameMappingsFromRequest();
PropertyNameMapper mapping = mappingsForClass(propertyMappings,
beanDesc.getBeanClass());
if (mapping == null) {
return beanProperties;
}
List<BeanPropertyWriter> propsToWrite = new ArrayList<BeanPropertyWriter>();
for (BeanPropertyWriter propWriter : beanProperties) {
String propName = propWriter.getName();
String outputName = mapping.nameMappings.get(propName);
if (outputName != null) {
BeanPropertyWriter modifiedWriter = new MyBeanPropertyWriter(
propWriter, outputName);
propsToWrite.add(modifiedWriter);
} else {
propsToWrite.add(propWriter);
}
}
return propsToWrite;
}
private List<PropertyNameMapper> getNameMappingsFromRequest() {
RequestAttributes requestAttribs = RequestContextHolder
.getRequestAttributes();
List<PropertyNameMapper> nameMappings = (List<PropertyNameMapper>) requestAttribs
.getAttribute("nameMappings",
RequestAttributes.SCOPE_REQUEST);
return nameMappings;
}
private PropertyNameMapper mappingsForClass(
List<PropertyNameMapper> nameMappings, Class<?> beanClass) {
for (PropertyNameMapper mapping : nameMappings) {
if (mapping.classToFilter.equals(beanClass)) {
return mapping;
}
}
return null;
}
}
Now, you need a custom Module to be able to customize the output using the above created BeanSerializerModifier:
public class MyModule extends Module {
#Override
public String getModuleName() {
return "Test Module";
}
#Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new MySerializerModifier());
}
#Override
public Version version() {
// Modify if you need to.
return Version.unknownVersion();
}
}
Now register this module with your ObjectMapper. You can get the Jackson HTTP message converter from your spring application context, and get its object mapper.
// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())
And that's it. This is the easiest way to customize serialization of your properties dynamically.
To use this, create a List of PropertyNameMappers and add it as an attribute (named "nameMappings" in this example) in the current request.
This is an example, not production-ready code. You might probably need to add null-checks and things like that. Also, a few minor adjustments might be needed based on the version of the libraries you are using.
If the solution doesn't work for you, let me know the problems you are facing.
You could inject a custom PropertyNamingStrategy into the ObjectMapper that's used in deserialization.
Just set fields into the PropertyNamingStrategy at runtime, assuming you can map them to something like the default JsonPropertyName (e.g. propertyA, propertyB, propertyC).
public class MyNamingStrategy extends PropertyNamingStrategy {
String propertyAName, propertyBName, propertyCName;
public MyNamingStrategy(String propANm, String propBNm, String propCNm) {
this.propertyAName = propANm;
//finish
}
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field,
String defaultName) {
return convert(defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config,
AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}
#Override
public String nameForSetterMethod(MapperConfig<?> config,
AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}
public String convert(String defaultName ){
return defaultName.replace("propertyA", propertyAName).replace( //finish
}
Finally you'd create an instance and inject it at runtime.
objectMapper.setNamingStrategy(myNamingStrategyInstance));
See this Cowtowncoder post for more on PropertyNamingStrategy:
Jackson 1.8: custom property naming strategies
Or this documentation:
github.com/FasterXML/jackson-docs/wiki/PropertyNamingStrategy

Force Jackson to add addional wrapping using annotations

I have the following class:
public class Message {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
When converting the instance to JSON using Jackson by default I get:
{"text":"Text"}
I would like to get:
{"message":{"text":"Text"}}
Is there any JAXB / Jackson annotation I can use to achieve my goal?
As a workaround, I can wrap my class with another class:
public class MessageWrapper {
private Message message;
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
}
or a more generic solution:
public class JsonObjectWrapper<T> {
/**
* Using a real map to allow wrapping multiple objects
*/
private Map<String, T> wrappedObjects = new HashMap<String, T>();
public JsonObjectWrapper() {
}
public JsonObjectWrapper(String name, T wrappedObject) {
this.wrappedObjects.put(name, wrappedObject);
}
#JsonAnyGetter
public Map<String, T> any() {
return wrappedObjects;
}
#JsonAnySetter
public void set(String name, T value) {
wrappedObjects.put(name, value);
}
}
Which can be used like so:
Message message = new Message();
message.setText("Text");
JsonObjectWrapper<Message> wrapper = new JsonObjectWrapper<Message>("message", message);
Is there any JAXB / Jackson annotation I can use to achieve my goal?
Thanks.
With Jackson 2.x use can use the following to enable wrapper without adding addition properties in the ObjectMapper
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
#JsonTypeName(value = "student")
public class Student {
private String name;
private String id;
}
On workaround: you don't absolutely need those getters/setters, so could just have:
public class MessageWrapper {
public Message message;
}
or perhaps add convenience constructor:
public class MessageWrapper {
public Message message;
#JsonCreator
public MessageWrapper(#JsonProperty("message") Message m) {
message = m;
}
}
There is a way to add wrapping too; with 1.9 you can use SerializationConfig.Feature.WRAP_ROOT_ELEMENT and DeserializationConfig.Feature.UNWRAP_ROOT_ELEMENT. And if you want to change the wrapper name (by default it is simply unqualified class name), you can use #JsonRootName annotation
Jackson 2.0 adds further dynamic options via ObjectReader and ObjectWriter, as well as JAX-RS annotations.
It was sad to learn that you must write custom serialization for the simple goal of wrapping a class with a labeled object. After playing around with writing a custom serializer, I concluded that the simplest solution is a generic wrapper. Here's perhaps a more simple implementation of your example above:
public final class JsonObjectWrapper {
private JsonObjectWrapper() {}
public static <E> Map<String, E> withLabel(String label, E wrappedObject) {
HashMap<String, E> map = new HashMap<String, E>();
map.put(label, wrappedObject);
return map;
}
}
Provided you don't mind the json having a capital m in message, then the simplest way to do this is to annotate your class with #JsonTypeInfo.
You would add:
#JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class Message {
// ...
}
to get {"Message":{"text":"Text"}}
A Simpler/Better way to do it:
#JsonRootName(value = "message")
public class Message { ...}
then use
new ObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true).writeValueAs...
If using spring, then in application.properties file add following:-
spring.jackson.serialization.WRAP_ROOT_VALUE=true
And then use #JsonRootName annotation on any of your class that you wish to serialize. e.g.
#JsonRootName("user")
public class User {
private String name;
private Integer age;
}
I have created a small jackson module that contains a #JsonWrapped annotation, that solves the problem. See here for the code: https://github.com/mwerlitz/jackson-wrapped
Your class would then look like:
public class Message {
#JsonWrapped("message")
private String text;
}

Categories