I want convert json string to one object.
The json looks like this:
{"receive":1413342268310}
And the object is like:
public class PositionBean {
private Long id;
private Date receive;
public void setReceive (Date receive) {
this.receive = receive;
}
public void setReceive (Long receive) {
this.receive = new Date (receive);
}
public Long getReceive () {
return receive.getTime ();
}
}
All the set and get methods I have to use in other class, so I can't delete one method.
When I invoke
objectMapper.readValue(str, PositionBean.class);
It prompt exception, the jackon don't know which method set, so I use #JsonIgnore, but I found the receive is null.
You can use annotation #JsonSetter to specify which method should be used as setter.
Example:
public class PositionBean {
private Long id;
private Date receive;
public void setReceive (Date receive) {
this.receive = receive;
}
#JsonSetter
public void setReceive (Long receive) {
this.receive = new Date (receive);
}
public Long getReceive () {
return receive.getTime ();
}
}
When you mark setter (e.g. setXXX) with #JsonIgnore it means that property XXX will be ignored.
From documentation:
For example, a "getter" method that would otherwise denote a property
(like, say, "getValue" to suggest property "value") to serialize,
would be ignored and no such property would be output unless another
annotation defines alternative method to use.
You can also use
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
This will not throw any mapping exception even if u dont have an appropriate field in the mapping class corresponding to a JSON field. Once configured u can use ur code for further processing.
objectMapper.readValue (str, PositionBean.class);
Related
I have a DTO class which has a property like:
#JsonIgnoreProperties(ignoreUnknown = true)
public class WPPostResponse {
#JsonProperty("featuredMedia")
Long featured_media;
public Long getFeatured_media() {
return featured_media;
}
public void setFeatured_media(Long featured_media) {
this.featured_media = featured_media;
}
}
The input JSON has the key featured_media. I convert the JSON string to the object and then sends it to the client response as JSON. I want the final response JSON to have featuredMedia as the key. I am however getting null as the value. If I remove the JsonProperty, it gives the value, but the key is having underscore. How to fix this? Thanks.
Always respect the Java naming conventions in your Java code. Use annotations to deal with Json not respecting them.
In this case, use JsonAlias
Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name
public class WPPostResponse {
#JsonAlias("featured_media")
Long featuredMedia;
public Long getFeaturedMedia() {
return featuredMedia;
}
public void setFeaturedMedia(Long featuredMedia) {
this.featuredMedia = featuredMedia;
}
}
You can use the JsonProperty on setters and getters to have different namings during serialization and deserialization
#JsonIgnoreProperties(ignoreUnknown = true)
public class WPPostResponse {
Long featuredMedia;
#JsonProperty("featuredMedia") // output will be featuredMedia
public Long getFeatured_media() {
return featuredMedia;
}
#JsonProperty("featured_media") // input should be featured_media
public void setFeatured_media(Long featured_media) {
this.featuredMedia = featured_media;
}
}
And also you set access level to #JsonProperty annotation
#JsonProperty(value = "featured_media", access = JsonProperty.Access.WRITE_ONLY)
I tried with #JsonIgnoreProperties and #JsonIgnore but no lucky..
This is my main:
#BodyParser.Of(BodyParser.Json.class)
public Result index() {
//I read the JSON Post request
JsonNode json = request().body().asJson();
Item[] items = Json.fromJson(json, Item[].class);
//I convert all the dueTime from string to jodatime DateTime, using the formatter with ISO 8601
items = addJodaTime(items);
//I sort the items by dueTime in jodatime DateTime format
Arrays.sort(items);
return ok(Json.toJson(items));
}
and where I put my ignore stuff, which is not working..
#JsonIgnoreProperties({"dueTimeNew"})
public static class Customer implements Comparable<Customer> {
public int id;
public String name;
public String duetime;
public String jointime;
#JsonIgnore
public DateTime dueTimeNew;
public DateTime getDueTime() {
return dueTimeNew;
}
any idea how to return only id and name?
You need to add #JsonIgnore to every field you need to ignore. If you don't do this, Jackson will add everything that is public or has a getter (a get??????????? method).
In your case, you have a lot of fields, and only dueTimeNew is being ignored... Also note that, because you have a getDueTime method that uses dueTimeNow, this will be added also. If the method was named getDueTimeNow it would be ignored probably.
how about creating a seperate class for response with just the fields u want to return ?
I'm calling this method and getting a 500 back from it.
In the debugger I'm able to step though it all the way to the return statement at the end. No problem, r is populated as expected after Response.build() is called, the status says 200 OK. But that's not what ends up getting produced. I've even told eclipse to break on any Exception.
#GET
#Path("/getAllAppMessagesAsXML")
#Produces({MediaType.TEXT_XML, MediaType.APPLICATION_XML})
public Response getAllAppMessagesXML(#QueryParam("applicationId") String applicationId){
ResponseList list = new ResponseList();
ArrayList<XmlMessageBean> xmlmessages = new ArrayList<>();
try {
List<AppMessage> messages = //Gets from a database
for(AppMessage m : messages){
XmlMessageBean xm = new XmlMessageBean();
xm.setId(m.getId());
xm.setApplicationId(m.getApplicationId());
xm.setMessageBody(m.getMessageBody());
xm.setMessageLevel(m.getMessageLevel());
xm.setMessageTitle(m.getMessageTitle());
xmlmessages.add(xm);
}
} catch (Exception e) {
logger.error("ERROR Failed to save Message AppMessageService.saveAppMessage()", e);
Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
list.setList(xmlmessages);
Response r = null;
try{
r = Response.status(Response.Status.OK).entity(list).build();
}catch(Exception e){
e.printStackTrace();
}
return r;
}
XmlMessageBean.java
#XmlRootElement(name="AppMessage")
#XmlAccessorType(XmlAccessType.FIELD)
public class XmlMessageBean {
#XmlElement
private Long id;
#XmlElement
private String applicationId;
#XmlElement
private String messageTitle;
#XmlElement
private String messageBody;
#XmlElement
private String messageLevel;
public XmlMessageBean(){
}
//getters and setters
}
ResponseList.java
#XmlRootElement(name = "ResponseList")
public class ResponseList {
public ResponseList(){
}
#XmlElement(name="list")
private List<XmlMessageBean> list;
public List<XmlMessageBean> getList() {
return list;
}
public void setList(List<XmlMessageBean> list) {
this.list = list;
}
}
I've got this all running in a jersey.servlet.ServletContainer
I'm stumped. I can't figure out how to get it to produce any kind of error message other than a generic 500. I've tried setting up an exception mapper as some other posts have mentioned but this also isn't picking anything up.
IllegalAnnotationException: Class has two properties of the same name "list"
Look at your two model classes XmlMessageBean and ResponseList. Do you see any difference? The main difference (and the cause for the error), is the #XmlAccessorType(XmlAccessType.FIELD) annotation (or lack there of). JAXB by default will look for the public properties (JavaBean getters/setters). So that's one property. But then you define another property by using the #XmlElement annotation on the field. The reason it works for XmlMessageBean is that it overrides the default public property lookup by changing it to XmlAccessType.FIELD
So you can simply annotate the ResponseList with #XmlAccessorType(XmlAccessType.FIELD) and it should work. You could also simply get rid of all the #XmlElement annotations, and get rid of #XmlAccessorType(XmlAccessType.FIELD), and it will still work, as it will look up the JavaBean properties. Generally, for me I only use the #XmlElement annotations when I need to change the name of the property, and just put it on the getter, for example.
private String messageBody;
#XmlElement(name = "body")
public String getMessageBody(){
return messageBody;l
}
Other than that, I normally leave out the annotation, and also the #XmlAccessorType annotation, and just let it resolve to the default behavior.
I was experimenting with Jackson 2.0 mixins to serialize a class with no annotations.
Simplified source code below. Note that I'm not using getters/setters, but it seemed like I should still be able to use mixins according to the documentation.
public class NoAnnotation {
private Date created;
private String name;
// make one with some data in it for the test
static NoAnnotation make() {
NoAnnotation na= new NoAnnotation();
na.created = new Date();
na.name = "FooBear";
return na;
}
// my Mixin "class"
static class JacksonMixIn {
JacksonMixIn(#JsonProperty("created") Date created,
#JsonProperty("name") String name)
{ /* do nothing */ }
}
// test code
public static void main(String[] args) throws Exception {
NoAnnotation na = NoAnnotation.make();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixInAnnotations(NoAnnotation.class, JacksonMixIn.class);
String jsonText = objectMapper.writeValueAsString(na);
System.out.println(jsonText);
}
}
When I run main I get
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.flyingspaniel.so.NoAnnotation and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.SerializationFeature.FAIL_ON_EMPTY_BEANS) )
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:51)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:25)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:108)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2407)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:1983)
at com.flyingspaniel.so.NoAnnotation.main(NoAnnotation.java:49)
When I follow the instructions in the Exception and add a line
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
I no longer get an exception, but the result is an empty JSON object, {}.
If I make the fields public it works, but that is not something I want to do, as it's not a reasonable object design.
I'm guessing that I am leaving out a basic "setThis" step somewhere, but don't know what. How can I get mixins to work in this situation?
I figured it out. If you want to access private fields, you need to play with the Visibility by adding the following line:
objectMapper.setVisibilityChecker(VisibilityChecker.Std.defaultInstance()
.withFieldVisibility(Visibility.ANY));
For protected fields, you could also use Visibility.PROTECTED_AND_PUBLIC.
Full example
// test code
public static void main(String[] args) throws Exception {
NoAnnotation na = NoAnnotation.make();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixInAnnotations(NoAnnotation.class, JacksonMixIn.class);
objectMapper.setVisibilityChecker(VisibilityChecker.Std.defaultInstance()
.withFieldVisibility(Visibility.ANY));
String jsonText = objectMapper.writeValueAsString(na);
System.out.println(jsonText);
}
If you want use the annotation mixin the correct way to declare it is:
static class JacksonMixIn {
#JsonProperty Date created;
#JsonProperty String name;
}
When done in this way you can control the fields to serialize simply including/excluding them from the mix in.
As mentioned in your self-answer, changing the field visibility checker will resolve this situation. As an alternative to modifying the ObjectMapper, this can be done with a purely annotation-based solution by using the #JsonAutoDetect annotation:
#JsonAutoDetect(fieldVisibility = Visibility.ANY)
static class JacksonMixIn {
JacksonMixIn(#JsonProperty("created") Date created,
#JsonProperty("id") int id)
{ /* do nothing */ }
}
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.