so I am using Jackson (together with Mongojack) to create POJO's of MongoDB Documents. My database looks something like this:
Document{ id:1, Document2{ value1:1 value2:2}}
I have created a POJO for Document, and for Document 2, and this generally works fine. The problem is that some places in my Database, Document2 has a value of NaN instead of being a nested document with several values, which leads to this error
ERROR [2015-07-21 16:01:26,809] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: 3b38d500d7657352
! com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class com.document1.document2] from Floating-point number (NaN); no one-double/Double-arg constructor/factory method
! at [Source: de.undercouch.bson4jackson.io.LittleEndianInputStream#534093c6; pos: 1975] (through reference chain: com.document1["document2"])
! at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.5.1.jar:2.5.1]
Not really sure what the best way to go about fixing this is. I guess what I'd want is for Jackson to recognize if Document2 is just :nan instead of a nested document, and just serialize it with no values or something?
It's really best if you can keep the data you're working reasonably consistent. That said, there may be a way to hack around this:
public class Document2 {
public Document2() { }
public Document2(double invalid)
{
System.out.print("invalid");
}
public void setValue1(int value1)
{
System.out.println("value1 " + value1);
}
public void setValue2(int value2)
{
System.out.println("value2 " + value2);
}
}
In the "happy" case, Jackson will use the default constructor and set the properties as given. In the NaN case, it will find the single-argument double constructor, and leave the other properties alone.
Related
When trying to convert a custom object Tag which has the below structure to json, it gives me the following error: java.lang.IllegalArgumentException: Infinite recursion because of getValueArray() function
public class Tag {
private String vr;
#JsonProperty("Value")
private JsonNode Value;
//getters and setters
public org.primefaces.model.TreeNode getValueArray() throws IOException
{
System.out.println("enter check");
TreeNode root = new DefaultTreeNode();
constructTree(Value, 1, root);
return root;
}
}
I have a getter for Value that returns String instead of JsonNode (for specific reason), and I have this getValueArray that causes the problem, Jackson calls this function when converting to json instead of using getValue (I know that as enter check are printed to console), actually when I remove this function it works, for some reason it calls this function and uses the returned TreeNode in it's conversion, I thought the problem might be that it gets confused with Jackson treeNode, so I returned org.primefaces.model.TreeNode to let it recognizes that this is primefaces TreeNode not Jackson TreeNode, I don't even know why it calls this function, and how to fix this.
the error said
java.lang.IllegalArgumentException: Infinite recursion (StackOverflowError) (through reference chain: org.primefaces.model.DefaultTreeNode["parent"]->org.primefaces.model.DefaultTreeNode["children"]->org.primefaces.model.TreeNodeChildren[0]->org.primefaces.model.DefaultTreeNode["parent"]................. and so on
I found a work around that works fine, as the problem is that Jackson uses this function getValueArray() as a getter in the serialization, because of it's name get something, I used
#JsonGetter("valueArray")
public JsonNode serializeValue()
{
return Value;
}
#JsonGetter("valueArray") lets me force Jackson to use the above function as getter for the non exist property valueArray which return the Value, now jackson will no longer uses getValueArray() function as getter.
I am trying to deserialize JSON of format
"{mapping:{MyType(type=\"A\", value=\"B\"):\"C\"}}"
into a class type
class MyMapping {
Map<MyType, String> mapping;
}
class MyType {
String type;
String value;
}
Since I have a map type, i added a KeyDeserializer to deserialize MyType(type=\"A\", value=\"B\")
But when i try to deserialize this i get an exception
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('(' (code 40)): was expecting a colon to separate field name and value
This is because it encounters ( in MyType(type=\"A\", value=\"B\") and it breaks there. If i put the whole key within double quotes \"MyType(type=\"A\", value=\"B\")\", it passes the the whole key to my deserializer.
Is there a way i can force it to escape the '(' char without having to put the whole key with quotes.
The string in your example is not valid JSON.
"{mapping:{MyType(type=\"A\", value=\"B\"):\"C\"}}"
You pointed out that the Jackson parser complains about the first (
If you want to use this particular string as a key you have to enclose it in quotes and escape internal quotes. Let's use a Javascript in a browser to do that, cause it's easy. From Chrome console...
> var c = {};
< undefined
> c['MyType(type="A", value="B")']='C';
< "C"
> JSON.stringify(c)
< "{"MyType(type=\"A\", value=\"B\")":"C"}"`
That's how Javascript escapes your key string as valid JSON.
KeyDeserializer
Based on Jackson 2.8 documentation for KeyDeserializer I would expect your KeyDeserializer to receive the whole key string. That's just how JSON works.
{"key-string":"value")
Of course "value" could be false, true, null or a number as well.
It's then up to you to parse the key-string and decide how to turn it into a key that your MyMapping can use.
Your Key String Appears Easy to Parse
Your KeyDeserializer can use a compiled regex pattern to get the two key properties as two regex 'groups'.
What if you don't want to parse the key string?
It sounds like you don't want to parse this key. There are several ways to avoid this. One key to this is to use a JSON format that makes it easy, such as ...
{"key":{"keyType":"A","keyValue":"B"}, "value":"C"}
Then you could use annotations to teach Jackson to work with your MyMapping class.
Such as (untested, just a sketch)
class MyMapping {
Map<MyType, String> mapping;
#JsonCreator
public MyMapping(Map<String,Object> input) {
Map<String,Object> key = (Map)input.get("key");
String value = (String)input.get("value");
MyType myKey = new MyType(key);
mapping = new HashMap<>();
mapping.put(myKey,value);
}
}
class MyType {
String type;
String value;
MyType (Map<String,Object> input) {
type = (String)input.getOrDefault("key","");
value = (String)input.getOrDefault("value","");
}
}
There's a very long list of problems with this example. You will be using the default object address based comparison in the Map, for example. I made this code short by ignoring likely ClassCastExceptions and other data problems. But the point here was not to write good code, or to try to understand the requirements, but simply to point out how you can get Jackson to parse the JSON for you.
There are many. other ways to achieve that. I just. picked the first one that came to mind.
I want to convert form data directly into a bean. Originally I used spring for that, but in my current project we are not allowed to use spring anymore so I tried to do something similiar with the help of Apache BeanUtils. My bean looks like this:
public class MyBean {
private String foo;
private String bar;
private List<FooBar> fooBars;
}
public class FooBar {
private int id;
}
After submitting the form the request.getParameterMap() method gives me the following map:
"foo" : "Some text",
"bar" : "Other text",
"foobars[0].id" : "1",
"foobars[1].id" : "2",
"foobars[2].id" : "3"
The code I use for the conversion looks like this:
MyBean bean = new MyBean();
BeanUtils.populate(bean, request.getParameterMap());
With the spring data binder it was no problem to convert those values into the bean, but the dot notation somehow does not work with BeanUtils. Does anyone know how the input must look like so that BeanUtils can transform foobars to a list of objects? Or maybe you know another library which is capable of that?
BeanUtils.populate does not seem to support nested properties:
This method uses Java reflection APIs to identify corresponding
"property setter" method names, and deals with setter arguments of
type String, boolean, int, long, float, and double. In addition, array
setters for these types (or the corresponding primitive types) can
also be identified.
I found this other method, BeanUtils.copyProperties, and here it is specified that
If the origin "bean" is actually a Map, it is assumed to contain
String-valued simple property names as the keys.
So I guess you have no way to do that with BeanUtils. But I may have a solution, using PropertyUtils. This class has a lot of static methods, among them there are:
setProperty
setNestedProperty
I have not tried it, but this is a possible approach:
MyBean bean = new MyBean();
for (Map.Entry<String, String> entry : request.getParameterMap())
{
try {
PropertyUtils.setProperty(bean, entry.getKey(), entry.getValue());
}
catch (NoSuchMethodException exc) {
PropertyUtils.setNestedProperty(bean, entry.getKey(), entry.getValue());
}
}
I would not know whether the conversion from String to Integer is automatic. Let me know.
I have a class Person and I want to deserialize a POJO from a JSON using jackson. Now,
the definition to Person class is something like :
class Person {
int id;
String name;
boolean isOldAge;
boolean hasSenseOfHumor;
.
.
.
}
Now my json is something like :
{
"id" : 1,
"isOldAge" : false
}
Now when I deserialize this into a POJO the values I will get would be :
[id=1,name="",isOldAge=false,hasSenseOfHumor=false]
i.e, the properties not mentioned in json will be assigned their default values.
So my problem lies here. Is there a way I can distinguish isOldAge from hasSenseOfHumor with respect to whether it is mentioned or provided for by the user or not.
Try to change the primitive boolean to the boxing Boolean type. The fields should be initialised with null values then.
If you cannot change field types of the class, then can read your JSON as map in advance as follows mapper.readValue(JSON, Map.class), and then reason about the presence of the boolean fields in the resulting map instance.
I need to serialize a couple of objects in my Android app and send them to web service.
The model classes for objects have various int fields which need to be converted into meaningful string representations from various arrays before sending to web service.
So, I am assuming that easiest way will be to use gson or xstream (JSON or XML - anything is fine) but with following method:
- I'll mark all existing int fields as transient and exclude them from serialization
- I'll create new get method per field. The get method will read value of corresponding integer and return its string representation.
But in either of 2 libraries - gson or xstream, I am unable to find way to serialize based on getters instead of fields. Please suggest.
And yes, I DO NOT need to deserialize the data back.
I think you need a wrapper class.
Consider this:
public class Blammy
{
private int gender;
... imagine the rest of the class.
}
public class BlammyWrapper
{
private String gender;
public BlammyWrapper(final Blammy blammy)
{
if (blammy.gender == 1)
{
gender = "Its a Boy";
}
else if (blammy.gender == 2)
{
gender = "girl";
}
else // always check your boundary conditions.
{
throw new InvalidArgumentException("Naughty blammy; unrecognized gender value");
}
public String gender()
{
return gender;
}
}
Ok, finally, I followed this approach:
1. Removed all resource arrays from my app code
2. Added enums with toString for each current array
3. Changed all int properties to be of corresponding enum type
4. Used XStream
5. Added a custom convertor for XStream for generic enum types where if it finds any property of type enum, then it will marshal it using toString method.
Thanks for all support btw. All your answers and comments atleast made me clear that my current code architecture needed drastic improvement.