Jackson: need a another method to be a setter - java

public class UrlTemplate extends AbstractBeanDefinition implements Serializable {
private List<HeaderField> header = new ArrayList<>();
#Tag("header")
public List<HeaderField> getHeader() {
return this.header;
}
#Node("header/header-field")
public void setHeader(HeaderField headerField) {
this.header.add(headerField);
}
public void setHeader(List<HeaderField> header) {
this.header = header;
}
}
Tag and Node annotation are used by other library, and I can't change method setHeader(HeaderField headerField).
I define a valid setter setHeader(List<HeaderField> header) for serializing, but when I try to serialize UrlTemplate to String and deserialize String to UrlTemplate, throw exception:
com.fasterxml.jackson.databind.JsonMappingException:
Conflicting setter definitions for property "header":
com.enniu.crawler.encreeper.core.domain.config.search.UrlTemplate#setHeader(1 params) vs
com.enniu.crawler.encreeper.core.domain.config.search.UrlTemplate#setHeader(1 params)
I think I may declare setHeader(List<HeaderField> header) to be the setter that Jackson take to deserialize, but I have no idea about how to do it with the Jackson.
Could any one give me some hint?

Try using JsonProperty annotation from jackson
#JsonProperty("header")
private Object headerJson;
public Object getHeaderJson() {
return status;
}
public void setHeaderJson(Object headerJson) {
this.headerJson= headerJson;
}
headerJson will be mapped to json header so it should resolve the conflict issue.

Related

How can I set an optional RequestBody field without it being deleted when I make the call?

I have a small program in spring-boot which through a get call having a #RequestBody returns me a message with all the specifications (in my case of cars)
public class CarsRequest implements Serializable {
private String name;
private String plate ;
private String price;
}
I would like to be able to make sure that if a field is set to null, it can still find the relative message with the other fields having a value, in my case, I wanted to put that the "name" field is optional in the RequestBody, is it possible to do this? I tried setting
public CarsResponse getCars(#RequestBody (required = false) CarsRequest request) throws IOException {
//some code
}
but then when I go to do the get it completely deletes the null field at the time of the get and therefore fails to do it
Just remove the #RequestBody annotation from the function and keep it as it is
public CarsResponse getCars(CarsRequest request) throws IOException {
//some code
}
Now all fields will be converted into query params and all will be optional, because query param by convention are optional
public class CarsRequest implements Serializable {
private String name;
private String plate ;
private String price;
}
And call like this
GET /someEndpoint?name=<value>&plate=null
But still if you want to make some params mandatory, then use javax.annotations or apply validation yourself.
EDIT: As asked in comment, if you are accepting JSON as parameter body then you can do one thing, you can accept it as String and then convert json to object inside function body
public CarsResponse getCars(#RequestParam(required = false) String request) throws IOException {
ObjectMapper mapper = new ObjectMapper();
CarRequest request = mapper.readValue(request,CarRequest.class);
// other code
}
and call it something like this
GET /someEndpoint?request="{ \"name\" : null, \"plate\": \"someValue\" }"
EDIT 2:
You can do one more thing if you want to keep sending json and have it transformed into object, you can declare a binder something like this
// Some controller class
class SomeController {
#Autowired
ObjectMapper mapper;
// Ommited methods here
#GetMapping("/carRequest")
public ResponseEntity<String> testBinder(#RequestParam CarRequest request) {
return ResponseEntity.ok("{\"success\": \"" + request.name+ "\"}");
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(CarRequest.class, new CarRequestEditor(mapper));
}
static class CarRequestEditor extends PropertyEditorSupport {
private ObjectMapper objectMapper;
public CarRequestEditor(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#Override
public void setAsText(String text) throws IllegalArgumentException
{
if (StringUtils.isEmpty(text)) {
setValue(new CarRequest());
} else {
try {
setValue(objectMapper.readValue(text, CarRequest.class));
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}
}
}
}
Please note that the client need to send the json URL encoded like this
http://localhost:8180/carRequest?request=%7B%22name%22%3"test"%7D
Hi you are using #RequestBody (required = false) CarsRequest
that means your CarsRequest object itself is optional
rather than you can use
#NotEmpty
private String plate ;
#NotEmpty
private String price;
You can make a single field optional by making it an Optional, in your case Optional<String>. If the field does not appear in the request body, then the Optional will be empty.
public class CarsRequest implements Serializable {
private String name;
private String plate;
private Optional<String> price;
}

Jackson 2.5 - JsonMappingException: Missing external type id property

I have this class with an External Property "contentType":
public class ContentEvent implements AbstractMessagingEvent{
#Valid
#JsonTypeInfo(include = JsonTypeInfo.As.EXTERNAL_PROPERTY, use = NAME, property = "contentType")
public final ContentValue message;
public ContentEvent(ContentValue message) {
this.message = message;
}
public ContentEvent() {
this(null);
}
public static ContentEvent example () {
return new ContentEvent(HostedFile.example());
}
}
"contentType" can be one of the following:
#JsonSubTypes({
#JsonSubTypes.Type(SecureFormSubmission.class),
#JsonSubTypes.Type(SecureFormInvitation.class),
#JsonSubTypes.Type(TextPlain.class),
#JsonSubTypes.Type(HostedFile.class),
#JsonSubTypes.Type(ExternalFile.class)
})
public interface ContentValue{
}
When I try to deserialize a JSON which is missing the "contentType" field, I get the following error:
com.fasterxml.jackson.databind.JsonMappingException: Missing external type id property 'contentType'
I tried adding a 'defaultImpl=NoClass.class' and also a defaultImpl=MyOwnCustomClass' and it clears the error, but the result is an object without any 'contentType'.
What I want is in case the 'contentType' field is missing, to use a default.
Thanks in advance.
You can annotate the class with #JsonIgnoreProperties(ignoreUnknown=true).

Java generics and jackson mapper

Hi I have the following classes:
public class MyRequest {
}
and
public class MyResponse {
}
and
public class Request<T> {
private String code;
private T request;
public setCode(String code) {
this.code = codel
}
public setRequest(T request) {
this.request = request
}
}
and following service request method:
public MyResponse getMyResponse(Request<MyRequest> myRequest) {
//process
try {
ObjectMapper mapper = new ObjectMapper();
String jsonInString = mapper.writeValueAsString(myRequest);
System.out.println(jsonInString);
} catch(Exception exp) {}
}
and following Json request is sending from JavaScript;
{
"code":"TESTCODE",
"request":null
}
After I send the request I an getting an Invalid Json error. Can anyone tell me what is wrong with my request Json or something else is wrong..?
By any chance are you using the model 'Request' as an inner class. If yes,
just try using the modifier static with 'Request'.
or rather move out the model 'Request' to a separate class
Non-static Inner classes by design contain a reference to the outer-class, which does cause problems in deserialization.
http://www.cowtowncoder.com/blog/archives/2010/08/entry_411.html

How not to display null values in json as response from jax-rs

I'm using jax rs and I want to create responses as json, code:
#Produces(MediaType.APPLICATION_JSON)
public class Rest{
#GET
Path("/Test")
public RestResponse restTest(){
return new RestResponse(100,"ERROR");
}
}
#XmlRootElement()
public class RestResponse{
private Integer code;
private String status;
private Integer id;
public RestResponse(Integer code, String status){
this.code = code;
this.status = status;
}
}
and I'm getting response as :
{"status":"ERROR","code":100,"id":null}
how to remove that "id":null value?
I want response to looks as :
{"status":"ERROR","code":100}
I need it because sometimes id is null and sometimes code is null and I don't want to display it.
With Genson you could do it like that:
// register a provider for your custom genson configuration.
#Provider
public class GensonCustomResolver implements ContextResolver<Genson> {
// configure the Genson instance
private final Genson genson = new Genson.Builder()
// if you want to support JAXB annotations
.with(new JAXBBundle())
.setSkipNull(true)
.create();
#Override
public Genson getContext(Class<?> type) {
return genson;
}
}

Java Jackson writing object twice

I have the following class which contains a String field and a Map field. I want to use Jackson to serialize it to json.
public class Mapping
private String mAttribute;
#JsonIgnore
private Map<String, String> mMap;
#JsonAnyGetter
public Map<String, String> getMap() {
//some logic to populate map
}
#JsonAnySetter
public void put(// some params) {
//some more logic
}
#JsonProperty(value = "attribute")
public String getAttribute() {
return mAttribute;
}
public void setAttribute(String aAttribute) {
mAttribute= aAttribute;
}
}
I instantiate a Mapping object and then use ObjectMapper to write it to a file.
ObjectMapper om = new ObjectMapper();
om.writeValue(destFile, myMappingObject);
For some reason, it's writing the Mapping instance myMappingObject twice. I'm assuming I've not set some visibility option somewhere but I don't know where.
The json looks like this, only it comes up twice in the file.
{
"attribute" : "someValue",
"map-key1" : "map-value1",
"map-key2" : "map-value2"
}
There's this, but apparently it was fixed in previous version of Jackson. I also tried changing the name of the method to random() and it still gets called twice (the number of times it should).
The problem had nothing to do with the above class. I was using another class that had a list of Mappings. Before:
public class MappingsList {
#JsonProperty
private List<Mapping> mappings;
public List<Mapping> getMappings() {return mappings;}
}
After:
public class MappingsList {
private List<Mapping> mappings;
#JsonProperty
public List<Mapping> getMappings() {return mappings;}
}
And it worked. The cause is that the ObjectMapper was seeing two (2) properties in the MappingsList class and therefore doing serialization on both. First it would create json for the mappings field and then again for the getMappings() method.

Categories

Resources