I want to save complex objects as a property of another object:
#Entity(noClassnameStored = true)
public class User {
......
#Embedded
public Map<String, List<Order>> orders;
......
}
#Embedded
public class Order {
String productName;
String description;
..........
}
Than map is set in code using setter:
Map<String, List<Order>> ordersMap = new HashMap<>();
ordersMap.put(...);
user.setOrders(ordersMap);
But in document 'User' every Order is saved with field 'className' in map 'orders' :
"1" :[ {"className": "com.domain.Order",
"productName" : "Milk",
"description": "Fresh"
}
]
What is needed to do to not save field 'className' for Order inside ordersMap?
Related
In my Spring Controller I cannot figure out how to retrieve correctly the result of a MongoDB with MongoTemplate aggregation. Below is the code from my Controller class:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("modality").is("check")),
Aggregation.group("name").count().as("check_count"),
Aggregation.project("name").and("check_count").as("check_count")
);
AggregationResults<Response> res = mongoTemplate.aggregate(aggregation, "user", Response.class);
Below the simple class of User and Response:
#Document(collection = "user")
class User{
#Id
private String id;
private String name;
private String modality;
//constructor and get/set
}
class Response{
private String name;
private string check_count;
//constructor and get/set
}
So I retrieve correctly my response but I do not see the name, that is always null:
{
"user": [
{
"name": null,
"check_count": 61
},
{
"name": null,
"check_count": 15
},...
What is wrong in my Aggregation.group ? Thanks
When you do the group aggregation, the pipeline that gets generated is mostly
{ "$group" : { "_id" : "$name", "check_count" : { "$sum" : 1}}}
So, the result of the group stage will have _id as the field, not name.
Subsequent, stage should use _id field.
Aggregation.project().and("_id").as("name").and("check_count").as("check_count");
Using this input
{
"personId": "uhqwe-8ewn-3129m",
"infoPerson": {
"name": "john",
"age" : 35
}
},
....
And this POJO
public class Person {
private String name;
private int age;
//getter/setter
}
I need to read it as
private Map<String,Person> pMap;
using the personId as the map key.
Is there a way to do it with jackson annotation?
As far as I know, it is not possible.
You can read a list and then convert it to a map.
Something like this
Map<String, Person> map = list.stream()
.collect(Collectors.toMap(Person::getPersonId, person -> person));
Is it possible in Jackson to get a reference to a previously-deserialized object from the same json string given it's id?
For example, I have the following Java classes:
public class Company {
List<Employee> employeeList;
List<Customer> customerList;
....
}
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Customer {
Long id;
...
}
public class Employee {
Long id;
Map<Customer, int> utilityMap;
...
}
I want to create a Company instance from a json string that looks like:
{
"customerList" : [ {
"id" : 0,
"name" : "customer0"
} ],
"employeeList" : [ {
"id" : 1,
"fullName" : "employee0",
"utilityMap" : {
"0" : 1
}
} ]
}
where the key 0 in utilityMap refers to the customer with id 0.
With KeyDeserializer I'm able to create a new Customer object, but I want the Map's key to be a reference to the corresponding object instead.
A simple solution would be to change the signature of Map<Customer, int> to be Map<Long, int>, but this not possible due to internal dependencies, is there another way to accomplish this without changing the model (similar to xml references)?
I'm wondering if there is any way to deserialize several JSON fields to just one Java property. E.g. given this JSON:
{
"id" : "1",
"name" : "Bartolo",
"address" : "whatever",
"phone" : "787312212"
}
deserialize it to this class:
public class Person {
public String id;
public String name:
#JsonProperty(names = {"address", "phone"}) //something like this
public String moreInfo;
}
so moreInfo equals to "whatever, 787312212" or something similar.
Is this possible without using custom deserializer?
You could use the #JsonCreator annotation like following:
String json = {"id" : "1", "name" : "Bartolo", "address" : "whatever", "phone" : "787312212" }
ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue(json , Person.class);
and in the constructor of your Person class add this
#JsonCreator
public Person(#JsonProperty("address") String address, #JsonProperty("phone") String phone) {
this.moreInfo = address + "," phone;
}
Another solution, if you don't want to know/handle other fields in the object, but decided to still receive these fields (maybe for logging purposes), then you can put them in a key-value store(Map)
#Getter
private final Map<String, Object> otherFields = new HashMap<>();
#JsonAnySetter
public void set(String name, Object value) {
otherFields.put(name, value);
}
Note that if you have any field with the same name as the Map field(like 'otherFields' in the example above), then you can get MismatchedInputException
Project I'm working on has the following come through via MQ:
example.json
{
"templateName": "testTemplate",
"to": [
"support#test.com"
],
"cc": [
"testCc#test.com
],
"bcc": [
"testBcc#test.com
],
"from": "testFrom#test.com",
"subject": "testSubject",
"replacementValues": {
"replacementValue1": "lorem",
"replacementValue2": "ipsum"
},
"jsonObject": {
//omitted for brevity
}
}
And as is, it will map to the following object:
NotificationV1.java
public class NotificationV1 {
private String templateName;
private List<String> to;
private List<String> cc;
private List<String> bcc;
private String from;
private String subject;
private Map<String, String> replacementValues;
private Map<String, String> images;
private Object jsonObject;
//getters & setters omitted for brevity
using the following mapper:
//no special config
notificationMessage = new ObjectMapper().readValue(jsonMessage, EmailNotificationMessage.class);
As part of a project wide refactor, the data class above has been altered to instead look like this:
NotificationV2.java
public class NotificationV2 {
private EmailHeaders emailHeaders;
private TemplateData templateData;
//getters and setters omitted
EmailHeaders.java
public class EmailHeaders {
private String from;
private List<String> toAddresses;
private List<String> ccAddresses;
private List<String> bccAddresses;
private String subject;
//getters and setters omitted
TemplateData.java
public class TemplateData {
private String templateName;
private Map<String, String> replacementValues;
private Map<String, String> images;
private Object jsonObject;
//getters and setters omitted
Naturally, the existing mapping throws errors around unrecognised properties in the json vs. the new object; cant map templateNAme, found emailHeaders and templateData, and so on. I cant change the structure of the json in order to fit the new object but havent found a resource that demonstrates a use case like the above for mapping. Are there annotations I can use on NotificationV2 and/or some sort of mapper configuration I can put together in order to hook all of this up?
To flatten your nested classes, you can use the annotation #JsonUnwrapped.
Example:
public class Parent {
public int age;
public Name name;
}
public class Name {
public String first, last;
}
This would normally be serialized as follows:
{
"age" : 18,
"name" : {
"first" : "Joey",
"last" : "Sixpack"
}
}
By updating the parent to use #JsonUnwrapped, we can flatten the nested objects:
public class Parent {
public int age;
#JsonUnwrapped
public Name name;
}
This will output the following:
{
"age" : 18,
"first" : "Joey",
"last" : "Sixpack"
}
See docs for more information