Jackson converting Map<CustomEntity, Integer> to JSON creates toString() from CustomEntity - java

I have custom Entity that i want to put as Json to my view page
But when i serialize it in map using ObjectMapper from Jackson i receive String created from toString() method
#Test
public void test() throws JsonProcessingException {
Map<ProductEntity, Integer> map = new HashMap<ProductEntity, Integer>();
ProductEntity prod = new ProductEntity();
prod.setIdProduct(1);
map.put(prod, 1);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(map));
}
Received: {"com.onlineshop.entity.ProductEntity#2":1}
where "com.onlineshop.entity.ProductEntity#2" is a String, not an object.
So how can i make it to be an Object?
I need exactly Map, not another type of Collection

You either need to annotate your ProductEntity object so Jackson knows how to serialize it or use a Mix In annotation if you are not able to modify the ProductEntity class. IIRC there are also global Jackson options you can set that tell it how to handle POJOs.
Since you didn't specify which version of Jackson you're using I can't link to the correct documents but there is a ton of information available on the Jackson sites on how to use annotations and mix ins.

Thanks to all for your answers.
I solved it by creating new DTO which contains :
private ProductEntity
private Integer
fields.

Related

Use multiple #JsonView (Jackson) in JAX-RS

I want to use multiple JsonViews to serialize a response.
For example, I have the object below:
public class A {
#JsonView(FieldView.A.class)
private String a;
#JsonView(FieldView.B.class)
private String b;
#JsonView(FieldView.C.class)
private String c;
}
And I want to add on the serialization the views A and B. But I did not find any solution for that , because I'm using ObjectMapper writeWithView that accepts just one view (Not a List), this way if I add A then B and C are removed from the response.
om.writeWithView(FieldView.A.class)
Is that a way to writeWithView using more than one view?
Thanks
After all I did a workaround. Using SimpleBeanPropertyFilter I created a list of the fields I want to discard with serializeAllExcept(Set<String> fields).
ObjectMapper mapper = new ObjectMapper();
SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter.serializeAllExcept(fields);
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);
mapper.setFilterProvider(filters);

Converting Object into "something else" before Serializing it using FasterXML Jackson

public void serialize(IPerson person, OutputStream output) throws Exception {}
public void deserialize(InputStream input) throws Exception {}
I have an interface named IPerson, it has basic functionality.
I want to serialize the person object and be able to deserialize it from the deserialize method.
However, the scenario is this I cannot use Java's serializable interface as I can't be sure what implementation of IPerson will be used.
I have chosen to use Jackson's FasterXML, using ObjectMapper m = new ObjectMapper();
The problem I am having is that since IPerson is an interface I cannot serialize it directly using mapper.writerValue(output, person), I figured I must convert this object into something else, say a ByteArray then serialize it?
Also, this would be converting this something else into an object when deserializing? I have minimal experience with what exactly I should convert this object to and how to do so? Any ideas?
When using the default ObjectMapper you will have to make sure the objects you serialize are Java Beans. For non-bean classes you can set field visibility using m.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); or annotate your class using #JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY).
For deserializing you will have to tell the ObjectMapper the target type. This can be done by providing a concrete implementation type to readValue or by storing the classname within the exported JSON. For this you can set m.enableDefaultTypingAsProperty(DefaultTyping.OBJECT_AND_NON_CONCRETE, "__class"); and annotate your objects with #JsonTypeInfo
ObjectMapper om = new ObjectMapper();
om.enableDefaultTypingAsProperty(DefaultTyping.OBJECT_AND_NON_CONCRETE, "__class");
IPerson value = new MyPerson();
String s = om.writeValueAsString(value);
IPerson d = om.readValue(s, IPerson.class);
using
interface IPerson {
void doSomething();
}
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "__class")
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
class MyPerson implements IPerson {
String name;
#Override
public void doSomething() {
}
}
Note that, you will need a default constructor for this to work or work with #JsonCreator and #JsonProperty (see jackson-annotations for details)

How to exclude fields during serialization of gson

I have two entities: Order and Item in a OneToMany relationship. Item belongs an Order, and the Order has a set of Items.
class Order{
#OneToMany(fetch = FetchType.EAGER, mappedBy = "id_order")
Set<Item> items;
}
class Item{
#ManyToOne(targetEntity = Order.class, fetch = FetchType.LAZY)
#JoinColumn(name = "id_order")
Order id_order;
}
I use gson to serialize Orders and send them to another machine, but a loop is being created during serialization, due to both orders and items having a reference to each other.
My goal is that when an Item is loaded, the field id_order should either be null or contain only the id, to avoid propagation. Does hibernate support this feature? Or can I exclude the field during serialization?
I already tried FetchType.LAZY on Item and catching Item inside an onLoad() Interceptor and setting its id_order to null. But it didn't work. I am trying to avoid writing a custom adapter or manually parsing all Items inside all Orders at every query.
I believe it has not much with Hibernate, but more with GSON. You should define serialization/deserialization rule.
Easiest way is to use #Expose annotation, to include/exclude given property from serialization/deserialization:
#Expose(serialize = false, deserialize = false)
Another way is to define custom adapters for givem class. WIth Adapter you can completely override the way GSON serialize or deserialize object.
For example:
public class YourAdapter implements JsonDeserializer<Order>, JsonSerializer<Order> {
#Override
public Orderde serialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
// your logic
}
#Override
public JsonElement serialize(Ordersrc, Type typeOfSrc, JsonSerializationContext context) {
// your logic
}
}
Finally initialize instance of your Gson parser:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Order.class, new YourAdapter())
.build();
If you want to avoid writting whole serialization, you could exclude your field by using #Expose, and then write adapter with pure instance of GSON in it, serialize/deserialize using that pure one and manually add that one field.
Another way of dealing with serialization/deserialization problem is to use ExclusionStrategy described here: https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/ExclusionStrategy.html
I know this doesnt answer the question derectly but might help others, GSON has an option to exclude based on a vairiables modifier.
Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.PRIVATE).create();

Jackson deserialization with anonymous classes

I have been searching all day for something that answers this, but I have not had a lot of luck thus far.
My question is straightforward: how do I deserialize an anonymous object correctly using Jackson.
private interface Interface1
{
int getValue();
}
public static void testAnonymousObject() throws IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
Interface1 testObject = new Interface1()
{
private final int value = 5;
#Override
public int getValue()
{
return value;
}
};
String json = mapper.writeValueAsString(testObject);
System.out.println("JSON = " + json);
Interface1 received = (Interface1) mapper.readValue(json, Object.class);
System.out.println(received);
}
The output of this is: JSON = ["com.foo.test.JacksonTest$1",{"value":5}] before I get an exception:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize Class com.foo.test.JacksonTest$1 (of type local/anonymous) as a Bean.
EDIT Just to clarify, both Jackson and XStream are able to serialize the object. But only XStream seems to be able to deserialize the object back. So this scenario can be made to work.
As of the time I am writing this, it seems that Jackson does not serialize inner classes or anonymous classes correctly. Other packages such as XStream and Kryo, do however.
Because inner classes do not have a default zero argument constructor (they have a hidden reference to the outer/parent class) Jackson cannot instantiate them.
you can check this link
Problem is not just about it being an inner class (which may or may not be problematic, depending on whether implementation is static or non-static), but also in that no type information is included -- all Jackson sees is type Interface1. To enable reading it back it is necessary to either include type information ("polymorphic type handling"), or to specify mapping between abstract type and implementation class.
Given that you are using an anonymous inner class, you would be able to support this usage by enabled so-called "default typing" (see ObjectMapper javadocs for enableDefaultTyping() or such).
But you may also need to implement specific strategy, if you do not want to enable type inclusion for all non-final types.
To see whether type id is included you can enable default typing with one of default options and have a look at JSON being produced: there should be an additional type id ("#class" property when class name is used as id).
A ready-to-use code-snippet for a generic JSON-deserialization to a Java POJO with Jackson using nested classes:
static class MyJSON {
private Map<String, Object> content = new HashMap<>();
#JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
#JsonAnySetter ensures a generic JSON-parsing and population.

Jackson: deserialization to a collection

I have this specific problem with JSON deserialization. Let's have this JSON structure:
{
"header":{
"objects":[
{"field":"value1"},
{"field":"value2"}
]
}
}
The JSON structure can't be altered as it comes from a 3rd party system.
Now let's have this simple POJO:
#JsonDeserialize(using=PojoDeserializer.class)
public class Pojo {
private string field;
//...getter, setter
}
The mentioned PojoDeserializer takes {"field": "value"} json string and deserializes it to the Pojo instance. So I can simply do the deserialization like this
Pojo instance = new
ObjectMapper().readValue("{\"field\":
\"value\"}", Pojo.class);
And here's my problem. Let's have another deserializer PojosCollectionDeserializer which takes the mentioned structure and deserializes it to a Collection of Pojo instances. I'd like to use it in a similar fashion as in the previous example:
Collection<Pojo> pojos = new ObjectMapper().readValue("{...}", Collection.class);
But this doesn't work as there is not defined that Collection should be created using the PojosCollectionDeserializer. Is there any way to achieve it?
I am not sure why are trying to explicitly specify deserializers, as it would all work just fine with something like:
public class Message {
public Header header; // or, if you prefer, getter and setter
}
public class Header {
public List<Pojo> objects;
}
public class Pojo {
public String field;
}
Message msg = objectMapper.readValue(json, Message.class);
without any additional configuration or annotations. There is no need to construct custom serializers or deserializers for simple cases like this.

Categories

Resources