Ratpack Jackson (json) render same object but different response format - json

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!

Related

Flattening a nested json with Jackson

I have a json schema as follows
{
"student" : {
"first name" : "abc",
"last name" : "efg"
"age" : 10,
"sex" : "m",
"subjects" : [
{"name" : "Math", "marks" : 10}.
{"name" : "Science", "marks" : 10}
]
}
}
I am trying to deserialize this into the following class structure :
class Student {
Map<String, Object> studentAttributes;
#JsonProperty("subjects")
List<Map<String, Object> subjects
}
When i try the jackson deserializer the subject attribute (from json) gets mapped into studentAttributes of the java class as string
Any suggestions ?

Can't serialize Json to Java object using Jackson ObjectMapper

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")

JSON Loading Lazy properties

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.

Spring Data Solr Repository Highlight HATEOAS

I have defined a #Highlight query on my Solr repository class which returns the interesting 'snipplets' info if I call it from another class/controller. However if I access the method through the implicit rest service exposed via #RepositoryRestResource ( e.g. http://localhost:8080/modules/search/findByDescriptionContaining?description=maths ) , it doesn't return any highlighting/snipplet info at all
#RepositoryRestResource
interface ModuleRepository extends SolrCrudRepository<Module, String>{
#Highlight(prefix = "<b>", postfix = "</b>")
HighlightPage<Module> findByDescriptionContaining(#Param(value = "description") String description, Pageable pageable)
}
so to recap, calling the auto exposed method will return this:
{
"_embedded" : {
"modules" : [ {
"name" : "science",
"description" : "a somewhat scientific course with some maths",
"_links" : {
"self" : {
"href" : "http://localhost:8080/modules/102"
},
"module" : {
"href" : "http://localhost:8080/modules/102"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/modules/search/findByDescriptionContaining?description=maths"
}
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
how can I get the highlighting info using the method above ?

Extracting content from a nested json

I am trying to used the gson library to parse a json file.I want to get a list of names and URLs of all states within a JSON.I am not able to understand the structure of the json object and how to retrieve this data,since any structure i create is returning null values . The sample structure of the JSON is
{
"states" : {
"state53" : {
"name" : "state53",
"url" : "http://cv4a.org/veterans-group-calls-accountability-va-funds-boost/",
"candidateElements" : [ {
"top" : 202,
"left" : 58,
"xpath" : "/HTML[1]/BODY[1]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/ARTICLE[1]/HEADER[1]/P[1]/A[1]",
"width" : 135,
"height" : 20
}, {
"top" : 1307,
"left" : 225,
"xpath" : "/HTML[1]/BODY[1]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/OL[1]/LI[1]/ARTICLE[1]/HEADER[1]/TIME[1]/A[1]",
"width" : 191,
"height" : 22
}, {
"top" : 1374,
"left" : 912,
"xpath" : "/HTML[1]/BODY[1]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/OL[1]/LI[1]/ARTICLE[1]/A[1]",
"width" : 78,
"height" : 38
}, {
"top" : 0,
"left" : 0,
"xpath" : "/HTML[1]/BODY[1]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/SECTION[1]/DIV[1]/P[1]/A[1]",
"width" : 169,
"height" : 18
} ],
"fanIn" : 1,
"fanOut" : 3,
"id" : 53,
"failedEvents" : [ "xpath /HTML[1]/BODY[1]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/SECTION[1]/DIV[1]/P[1]/A[1]" ]
},
"state9" : {
"name" : "state9",
"url" : "http://cv4a.org/blog/#",
"candidateElements" : [ ],
"fanIn" : 1,
"fanOut" : 0,
"id" : 9,
"failedEvents" : [ ]
},
public static void main(String[] args) {
JsonElement jsonElement = new JsonParser().parse(jsonString);
JsonObject statesObj = jsonElement.getAsJsonObject();
statesObj = statesObj.getAsJsonObject("states");
final Set<Map.Entry<String, JsonElement>> statesEntries = statesObj.entrySet();
for (Map.Entry<String, JsonElement> state : statesEntries) {
JsonObject stateObj = state.getValue().getAsJsonObject();
String name = stateObj.get("name").getAsString();
//....
}
}
Or you can create classes (like State, CandidateElement) with fields (name, url, e.t.c) and use auto serialization/deserialization. See documentation