I'm writing a Java spring boot mvc application with possibility of data export / import. I wrote a wrapper class, that shoud serialize / deserialize data for Student class. It works good for export, but during import an error appears
com.fasterxml.jackson.databind.exc.MismatchedInputException: Root name
'student' does not match expected ('students') for type [simple type,
class org.bajiepka.courseApp.wrappers.Response] at [Source:
(FileInputStream); line: 2, column: 3]
here is my maven jackson dependency:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
I use wrapper class Response for list of students,
package org.bajiepka.courseApp.wrappers;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import org.bajiepka.courseApp.domain.Student;
#JsonRootName("import")
public class Response {
private Iterable<Student> students;
#JsonProperty("students")
public Iterable<Student> getStudents(){
return students;
}
public void setStudents(Iterable<Student> students) {
this.students = students;
}
}
And this is my Student class:
#Data
#Entity
public class Student {
private #Id #GeneratedValue Long id;
private #Version int version;
#NotNull
private String name;
private String address;
private String phone;
private Integer gradeBook;
private float averageProgress;
public Student() {}
}
}
This is the method that created an export file:
public String write(boolean toFile){
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter();
try {
String result = writer.writeValueAsString(response);
if (toFile){
result = fileService.writeToFile(result);
}
return result;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return "";
}
after export i get the file with json, that i can't convert to java objects:
{
"student" : [ {
"id" : 1,
"version" : 0,
"name" : "Rachel Jessica Parker",
"address" : "Pentaho",
"phone" : "111-22-33",
"gradeBook" : 1000121,
"averageProgress" : 0.0
}, {
"id" : 2,
"version" : 0,
"name" : "Bobby Jackson Junior",
"address" : "Illinois",
"phone" : "222-33-44",
"gradeBook" : 1000122,
"averageProgress" : 0.0
}, {
"id" : 3,
"version" : 0,
"name" : "Sammy Smith Carlson",
"address" : "Pennsylvania",
"phone" : "333-44-55",
"gradeBook" : 1000123,
"averageProgress" : 0.0
}, {
"id" : 4,
"version" : 0,
"name" : "Harry Dale Harrison",
"address" : "Detroit",
"phone" : "444-55-66",
"gradeBook" : 1000124,
"averageProgress" : 0.0
}, {
"id" : 5,
"version" : 0,
"name" : "Lindsey jefferson Conly",
"address" : "Washington",
"phone" : "555-66-77",
"gradeBook" : 1000125,
"averageProgress" : 0.0
}, {
"id" : 6,
"version" : 0,
"name" : "Mo Williams Jr.",
"address" : "New York",
"phone" : "666-77-88",
"gradeBook" : 1000126,
"averageProgress" : 0.0
} ]
}
And finally this is the method for conversion:
#GetMapping(value = "/import")
public String importFile(#RequestParam Long id){
File importFile = new File(exchangeFileService.findById(id).getName());
if (importFile.exists()) {
try (FileInputStream stream = new FileInputStream(importFile)) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
TypeReference<Response> typeReference = new TypeReference<>(){};
Response response = mapper.readValue(stream, typeReference);
} catch (IOException e) {
e.printStackTrace();
}
}
return "redirect:/exchange/upload";
}
i get mentioned above MismatchInputException at mapper.readValue(stream, typeReference)
ObjectMapper should return me a Response with a list of students but it doesn't...
#UPDATE
I've managed to find the cause of the error.
During the Object -> Json serialization jackson root name is missed...
I've added manually
{
**"import" : {**
"student" : [ {
"id" : 1,
"version" : 0,
"name" : "Rachel Jessica Parker",
"address" : "Pentaho",
"phone" : "111-22-33",
"gradeBook" : 1000121,
"averageProgress" : 0.0
}, ... ]
,
"course" : [ {
"id" : 7,
"version" : 0,
"name" : "Physics for 9-th grade",
"number" : 100292910,
"cost" : 25000.0,
"modules" : 0,
"max_COURSES_PER_STUDENT" : 3,
"modules_PER_COURSE" : 10
}, ... ]
**}**
}
Also i've managed to extend Response class, as it was required... Now i'm trying to find the reason in ObjectMapper during serialization...
The problem was caused due to Java object -> Json serialization without root level.
To add it to Json i've just added it at mapper by withRootName() method and everything works well from now on!
mapper.writer().withDefaultPrettyPrinter().withRootName("import")
Related
I'm having my first attempt at using JSON. I've got some code that serialises my objects just fine, but trying to deserialise I get a MismatchedInputException, Cannot deserialize instance of com.john.irrigator3.irrigation.WateringSchedule out of START_ARRAY token
I guess Jackson is having trouble deserialising an array in my WateringScheduleCollection and I've tried changing the names of the method for adding to the array, creating no argument constructors, but I'm stuck. Can someone tell me where I'm going wring please?
WaterScheduleCollection:
public class WateringScheduleCollection {
Map<String, WateringSchedule> schedules = new LinkedHashMap<>();
public void removeSchedule(String name) {
schedules.remove(name);
}
public void addSchedule(WateringSchedule wateringSchedule) {
schedules.put(wateringSchedule.getName(), wateringSchedule);
}
public Map<String, WateringSchedule> getSchedules() {
return schedules;
}
}
WateringSchedule:
public class WateringSchedule {
String name;
ArrayList<WateringRoutine> wateringRoutines;
SeasonLimits seasonLimits = null;
int sprinkleDuration = 30;
public WateringSchedule() {
wateringRoutines = new ArrayList<WateringRoutine>();
}
public WateringSchedule(List<WateringRoutine> wateringRoutines) {
this();
for (WateringRoutine wateringRoutine : wateringRoutines) {
addWateringRoutine(wateringRoutine);
}
}
public void addWateringRoutine(WateringRoutine wateringRoutine) {
wateringRoutines.add(wateringRoutine);
}
public ArrayList<WateringRoutine> getWateringRoutines() {
return wateringRoutines;
}
Serialising works fine with this:
public void writeFile(){
WateringRoutine wr1 = new WateringRoutine(0,1,10);
WateringRoutine wr2 = new WateringRoutine(1,2,100);
WateringRoutine wr3 = new WateringRoutine(2,3,1000);
SeasonLimits seasonLimits = new SeasonLimits(4, 1, 6, 7);
WateringSchedule wateringSchedule1 = new WateringSchedule();
wateringSchedule1.setName("wateringSchedule1");
wateringSchedule1.addWateringRoutine(wr1);
wateringSchedule1.addWateringRoutine(wr2);
WateringSchedule wateringSchedule2 = new WateringSchedule();
wateringSchedule2.setName("wateringSchedule2");
wateringSchedule2.addWateringRoutine(wr2);
wateringSchedule2.addWateringRoutine(wr3);
WateringSchedule wateringSchedule3 = new WateringSchedule();
wateringSchedule3.setName("wateringSchedule3");
wateringSchedule3.addWateringRoutine(wr1);
wateringSchedule3.addWateringRoutine(wr2);
wateringSchedule3.addWateringRoutine(wr3);
wateringSchedule3.setSeasonLimits(seasonLimits);
WateringScheduleCollection wateringScheduleCollection = new WateringScheduleCollection();
wateringScheduleCollection.addSchedule(wateringSchedule1);
wateringScheduleCollection.addSchedule(wateringSchedule2);
wateringScheduleCollection.addSchedule(wateringSchedule3);
ObjectMapper mapper = new ObjectMapper();
mapper.getSerializerProvider().setNullKeySerializer(new MyDtoNullKeySerializer());
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = null;
try {
json = mapper.writeValueAsString(wateringScheduleCollection);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println(json);
}
giving this output:
{
"schedules" : {
"wateringSchedule1" : {
"name" : "wateringSchedule1",
"wateringRoutines" : [ {
"secsWatering" : 1,
"hoursAllowedWithoutWater" : 10.0,
"scheduleSprinkle" : false,
"age" : 0
}, {
"secsWatering" : 2,
"hoursAllowedWithoutWater" : 100.0,
"scheduleSprinkle" : false,
"age" : 1
} ],
"seasonLimits" : null,
"sprinkleDuration" : 30
},
"wateringSchedule2" : {
"name" : "wateringSchedule2",
"wateringRoutines" : [ {
"secsWatering" : 2,
"hoursAllowedWithoutWater" : 100.0,
"scheduleSprinkle" : false,
"age" : 1
}, {
"secsWatering" : 3,
"hoursAllowedWithoutWater" : 1000.0,
"scheduleSprinkle" : false,
"age" : 2
} ],
"seasonLimits" : null,
"sprinkleDuration" : 30
},
"wateringSchedule3" : {
"name" : "wateringSchedule3",
"wateringRoutines" : [ {
"secsWatering" : 1,
"hoursAllowedWithoutWater" : 10.0,
"scheduleSprinkle" : false,
"age" : 0
}, {
"secsWatering" : 2,
"hoursAllowedWithoutWater" : 100.0,
"scheduleSprinkle" : false,
"age" : 1
}, {
"secsWatering" : 3,
"hoursAllowedWithoutWater" : 1000.0,
"scheduleSprinkle" : false,
"age" : 2
} ],
"seasonLimits" : {
"startOfSeason" : 1554098900367,
"endOfSeason" : 1559887700367,
"monthStart" : 4,
"dayStart" : 1,
"monthEnd" : 6,
"dayEnd" : 7
},
"sprinkleDuration" : 30
}
}
}
but trying to deserialise with this code:
public void readFile() {
ObjectMapper objectMapper = new ObjectMapper();
try {
WateringScheduleCollection wsc = objectMapper.readValue(new File(testPath+fileName), WateringScheduleCollection.class);
System.out.println(wsc.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
results in:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.john.irrigator3.irrigation.WateringSchedule` out of START_ARRAY token
at [Source: (File); line: 3, column: 15] (through reference chain: com.john.irrigator3.irrigation.WateringScheduleCollection["schedules"]->java.util.LinkedHashMap["schedule"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
I think Jackson has problem with you choosing Collection implementations (LinkedHashMap, ArrayList), rather than interfaces (Map, List).
Normally Jackson will pick some defaults (e.g. ArrayList for List I'm guessing).
Please refer to this Answer for specifying expected interface implementations:
Jackson - How to specify a single implementation for interface-referenced deserialization?
I've just found out what I was doing wrong. I was writing the JSON to a file, then reading the file to deserialise. Well that's what I thought I was doing. Turns out, I was writing one file and reading a different one. Having seen that stupid mistake, the JSON just worked, serialising and deser deserialising without a problem.
Thanks for your answer, but what I really need is a solution to stupidity.
While saving json object containing multiple jsons, the json object is being saved as a single array instead of multiple rows.
sample json:
[
{
"id" : 1, -- this is not a primary key and not unique but cannot be null
"name" : "John Doe",
"phone" : [
{ "type" : "home", "ref" : "111-111-1234"},
{ "type" : "work", "ref" : "222-222-2222"}
]
},
{
"id" : 2, -- this is not a primary key and not unique but cannot be null
"name" : "Jane Doe",
"phone" : [
{ "type" : "home", "ref" : "111-111-1234"},
{ "type" : "work", "ref" : "222-222-2222"}
]
}
]
This is what i need after saving in the database
id name phone
1 John Doe { "type" : "home", "ref" : "111-111-1234"}
1 John Doe { "type" : "work", "ref" : "222-222-2222"}
2 Jane Doe { "type" : "home", "ref" : "111-111-1234"}
2 Jane Doe { "type" : "work", "ref" : "222-222-2222"}
This is what I am getting
id name phone
1 John Doe [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]
2 Jane Doe [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]
here is how i am parsing the json object to pojo and saving to db
#Entity
#Table(name="person")
public class person{
private Integer id;
private String name;
private String phone;
#Transient
JsonNode phoneJson;
private static OhjectMapper mapper = new ObjectMapper();
getter/setter
#Transient
public JsonNode getPhoneJson(){
return phoneJson;
}
public void setPhoneJson(JsonNode phoneJson){
this.phoneJson = phoneJson;
}
#JsonIgnore
#Column(name="phone")
public String getPhone() throws Exception{
return mapper.writeValueAsString(phoneJson);
}
public void setPhone(String phone) throws Exception{
this.phone = mapper.readTree(phone);
}
}
dao- save
personRepository.save(person)
any help would be appreciated.
UPDATE
Multiple jSON Column
[
{
"id" : 1, -- this primary key and not unique but cannot be null
"name" : { --this element can be empty/null
"first" : "John",
"last" : "Doe"
},
"phone" : [
{ "type" : "home", "ref" : 1111111234},
{ "type" : "work", "ref" : 2222222222}
]
},
{
"id" : 2, -- this primary key and not unique but cannot be null
"name" : {
"first" : "Jane",
"last" : "Doe"
},
"phone" : [
{ "type" : "home", "ref" : 1111111234},
{ "type" : "work", "ref" : 2222222222}
]
}
]
how do i get result as below
id name phone
1 [{John},{Doe}] { "type" : "home", "ref" : "111-111-1234"}
1 [{John},{Doe}] { "type" : "work", "ref" : "222-222-2222"}
2 [{Jane},{Doe}] { "type" : "home", "ref" : "111-111-1234"}
2 [{Jane},{Doe}] { "type" : "work", "ref" : "222-222-2222"}
You need to duplicate Person objects n times where n is size of phone array. To make it clear, I propose, to create two separate models which we can use separately for parsing JSON and saving in DB. Below you can find simple example which:
Parses JSON to List<JsonPerson>
Converts List<JsonPerson> to List<Person>
Prints List<Person> (you can save it to DB)
Example:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.type.CollectionType;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
CollectionType personsType = mapper.getTypeFactory().constructCollectionType(List.class, JsonPerson.class);
// parse
List<JsonPerson> jsonPersons = mapper.readValue(jsonFile, personsType);
// convert
List<Person> persons = jsonPersons.stream()
.map(p -> p.mapTo(mapper))
.flatMap(List::stream)
.collect(Collectors.toList());
persons.forEach(System.out::println);
// save persons to DB
// ...
}
}
class JsonPerson {
private Integer id;
private String name;
private ArrayNode phone;
public List<Person> mapTo(ObjectMapper mapper) {
List<Person> persons = new ArrayList<>();
phone.elements().forEachRemaining(phone -> {
persons.add(map(mapper, phone));
});
return persons;
}
private Person map(ObjectMapper mapper, JsonNode p) {
Person person = new Person();
person.setId(id);
person.setName(name);
try {
person.setPhone(mapper.writeValueAsString(p));
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
return person;
}
// getters, setters, toString
}
class Person {
private Integer id;
private String name;
private String phone;
// getters, setters, toString
}
Above code prints:
Person{id=1, name='John Doe', phone='{"type":"home","ref":"111-111-1234"}'}
Person{id=1, name='John Doe', phone='{"type":"work","ref":"222-222-2222"}'}
Person{id=2, name='Jane Doe', phone='{"type":"home","ref":"111-111-1234"}'}
Person{id=2, name='Jane Doe', phone='{"type":"work","ref":"222-222-2222"}'}
Above code separates parsing JSON from other parts. Also, do not create ObjectMapper in each POJO. POJO should not know anything about ObjectMapper and Jackson.
Update
Because name is JSON Object you can create new POJO - Name with first and last properties or treat it similarly to phone and deserialise to JsonNode:
class JsonPerson {
private Integer id;
private JsonNode name;
private ArrayNode phone;
public List<Person> mapTo(ObjectMapper mapper) {
List<Person> persons = new ArrayList<>();
phone.elements().forEachRemaining(phone -> {
persons.add(map(mapper, phone));
});
return persons;
}
private Person map(ObjectMapper mapper, JsonNode p) {
Person person = new Person();
person.setId(id);
person.setName(getNameAsString());
try {
person.setPhone(mapper.writeValueAsString(p));
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
return person;
}
private String getNameAsString() {
if (name == null) {
return null;
}
StringBuilder builder = new StringBuilder();
if (name.isObject()) {
ObjectNode nameObject = (ObjectNode) name;
builder.append("[");
builder.append("{").append(nameObject.get("first")).append("}");
builder.append(",");
builder.append("{").append(nameObject.get("last")).append("}");
builder.append("]");
}
return builder.toString();
}
// getters, setters, toString
}
After change above code should print:
Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}
Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}
getNameAsString method is simplified, you need to handle all corner cases and create String representation better for null, empty and semi-empty nodes.
I have 2 entities
Product:
#Id #GeneratedValue
private Long id;
private String name;
private String description;
#ManyToOne(fetch = FetchType.LAZY)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
private Product parentProduct;
#OneToMany(fetch = FetchType.LAZY)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
private Set<Product> childProduct;
#OneToMany(mappedBy="product", fetch = FetchType.LAZY)
#JsonManagedReference #JsonInclude(JsonInclude.Include.NON_EMPTY)
private Set<Image> images;
Image:
#Id
#GeneratedValue
private Long id;
private String type;
#ManyToOne(fetch = FetchType.LAZY, optional = true)
#JsonBackReference
#JsonInclude(JsonInclude.Include.NON_EMPTY)
private Product product;
the lazy relationship are being loaded when I call from a RestController but when I call from my main method (Spring Boot) they came empty.
What I do to maintain lazy when Json serialize.
json return:
[ {
"id" : 1,
"name" : "Passatempo Pacote",
"description" : "Cookies Package",
"images" : [ {
"id" : 2,
"type" : "png"
}, {
"id" : 1,
"type" : "jpeg"
} ]
}, {
"id" : 2,
"name" : "Passatempo",
"description" : "Cookies",
"parentProduct" : {
"id" : 1,
"name" : "Passatempo Pacote",
"description" : "Cookies Package",
"images" : [ {
"id" : 2,
"type" : "png"
}, {
"id" : 1,
"type" : "jpeg"
} ]
}
} ]
Images must be empty because lazy config on property
The Json Serializer will call the get method, which will load your lazy field.
If you don't want these lazy field in json, you could annotate them #JsonIgnore.
#JsonInclude(JsonInclude.Include.NON_EMPTY) means the field will be ignored only if it's empty.
Use fetch = FetchType.EAGER instead of fetch = FetchType.LAZY.
I have searched and searched but found no answer/solution so am resorting to asking this myself.
Using fasterxml jackson 2.8.7
I have a complex map that I pass to angular and get back via a Spring mapping as a JSON string.
Map:
Map<String, List<TableModel>> tableEntryData = new LinkedHashMap<>();
It is a Map of List of TableModel. Table model is an interface that extends into several concrete classes. So using TableModel as the object type allows me to put whatever concrete class extended from TableModel into the List.
I can pass this to angular fine using:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
tableEntryJSON = mapper.writeValueAsString( tableEntryData );
But when I try to deserialize the JSON:
tableEntryData = mapper.readValue(tableEntryJSON,
new TypeReference<LinkedHashMap<String, LinkedList<TableModel>>>() {} );
I am facing this exception:
com.fasterxml.jackson.databind.JsonMappingException: (was
java.lang.NullPointerException) (through reference chain:
java.util.LinkedHashMap["Table_A_List"]->java.util.LinkedList[8])
Now my data Map (tableEntryData) contains data like this:
Map = {
[Table_A_List] = {LinkedList of 13 objects of TableA},
[Table_B_List] = {LinkedList of 2 objects of TableB}
}
Where Table_A_List and Table_B_List are map keys. TableA and TabelB are classes that implement interface TableModel.
The JSON created is like this:
{ "TABLE_A_List" : [ {
"deserializeType" : "TableA",
"amount" : 0.0, }, {
"deserializeType" : "TableA",
"amount" : 8.3, }, {
"deserializeType" : "TableA",
"amount" : 20.0, }, {
"deserializeType" : "TableA",
"amount" : 19.4, }, {
"deserializeType" : "TableA",
"amount" : 33.9, }, {
"deserializeType" : "TableA",
"amount" : 11.3, }, {
"deserializeType" : "TableA",
"amount" : 23.6, },{
"deserializeType" : "TableA",
"amount" : 2.6, },{
"deserializeType" : "TableA",
"amount" : 3.6, },{
"deserializeType" : "TableA",
"amount" : 23.0, },{
"deserializeType" : "TableA",
"amount" : 230.6, },{
"deserializeType" : "TableA",
"amount" : 23.8, },{
"deserializeType" : "TableA",
"amount" : 11.1, }, ],
"TABLE_B_List" : [ {
"deserializeType" : "TableB",
"code" : 9, }, {
"deserializeType" : "TableB",
"code" : 1, }, ] }
which seems correct.
In order to correctly deserialize concrete classes from the interface, I have defined things as follows
TableModel:
#JsonDeserialize(using = ModelInstanceDeserializer.class)
#JsonIgnoreProperties(ignoreUnknown = true)
public interface TableModel
{
....
}
TableA:
#JsonDeserialize(as = TableA.class)
#JsonIgnoreProperties(ignoreUnknown = true)
public class TableA implements Serializable
{
String deserializeType = "TableA"; //This is for providing type info that helps with the deserialization since JSON mapper erases type info inside Maps/Lists
//public getters for fields
}
TableB:
#JsonDeserialize(as = TableB.class)
#JsonIgnoreProperties(ignoreUnknown = true)
public class TableB implements Serializable
{
String deserializeType = "TableB"; //This is for providing type info that helps with the deserialization since JSON mapper erases type info inside Maps/Lists
//public getters for fields
}
Then I created a deserializer class ModelInstanceDeserializer as well:
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ModelInstanceDeserializer extends JsonDeserializer<TableModel> {
#Override
public TableModel deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends TableModel> instanceClass = null;
String type = "";
if (root.has("deserializeType")) {
type = root.get("deserializeType").asText();
}
if (type.equals("TableA")) {
instanceClass = TableA.class;
} else if (type.equals("TableA")) {
instanceClass = TableB.class;
}
if (instanceClass == null) {
return null;
}
return mapper.readValue(jp, instanceClass);
}
}
Now while this baby works somewhat, there is a problem. The deserializer reads the second map entry as a List that is part of the first map entry. What is happening is that the deserializer seems to read two records at a time from the TABLE_A_List JSON and as a result ends up including TABLE_B_List on the 7th entry:
{
"TABLE_B_List" : [ {
"deserializeType" : "TableB",
"code" : 9,
}, {
"deserializeType" : "TableB",
"code" : 1,
}, ]
}
There are 13 total entries in TABLE_A_List.
So can anybody point me on how to do this correctly. I think I need to configure the deserializer better or something else is the issue.
Yes I can always go back and get rid of the TableModel approach and use something better but that is not the point. It would require too much code change at this point. I need to make this work correctly.
Found the solution a few minutes later despite having lost my brains over this for 2 days.
Use:
return mapper.readValue(root.toString(), instanceClass);
Instead of:
return mapper.readValue(jp, instanceClass);
readValue on JsonParser ends up incrementing the root node. It was a logical error + lack of bloody guides.
Thanks everyone for your answers! :*
I'm using RatPack 1.1.1 with Jackson and it renders the same object "Product" differently. The first "Product" within my main object is returned with the attribute "productCode" but for the others for the same product, it returns only an attribute value "product" with the value of the "productCode"!
Why? is it normal?
Response from the rendering:
ProductCharacteristics=[ {
"id" : 1,
"product" : {
"productCode" : "cold-brew"
},
"attributeCode" : "family",
"attributeValue" : "Kits",
}, {
"id" : 2,
"product" : "cold-brew",
"attributeCode" : "Couleur",
"attributeValue" : "Noir",
}, {
"id" : 3,
"product" : "cold-brew",
"attributeCode" : "Matériaux",
"attributeValue" : "Verre-Plastique",
}
]
Definition of my entity ProductCharacteristic:
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#ToString
class ProductCharacteristic {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#JoinColumn(name = "product_code")
#ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
Product product;
}
Definition of my entity Product:
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="productCode")
#ToString
public class Product {
#Id
String productCode;
}
Why the response is not like that:
ProductCharacteristics=[ {
"id" : 1,
"product" : {
"productCode" : "cold-brew"
},
"attributeCode" : "family",
"attributeValue" : "Kits",
}, {
"id" : 2,
"product" : {
"productCode" : "cold-brew"
},
"attributeCode" : "Couleur",
"attributeValue" : "Noir",
}, {
"id" : 3,
"product" : {
"productCode" : "cold-brew"
},
"attributeCode" : "Matériaux",
"attributeValue" : "Verre-Plastique",
}
]
Thanks for your help!