I have the following json
{
"root": {
"status": "UP",
"connection1": {
"status": "UP"
},
"connection2": {
"status": "UP"
}
}
}
Also i have the following POJO classes i want to convert JSON into
#JsonIgnoreProperties(ignoreUnknown = true)
public class POJO {
#JsonProperty("root")
#JsonDeserialize(using = RootDeserializer.class)
private Root root;
//getters + setters
}
public class Root {
private boolean isAlive;
private List<Connection> connections;
public Root(boolean isAlive, List<Connection> connections) {
this.isAlive = isAlive;
this.connections = connections;
}
//getters + setters
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Connection {
private String status;
//getters + setters
}
And finally i have this deserializer to convert json into Root instance
public class RootDeserializer extends JsonDeserializer<Root> {
private static final String CONNECTION_PREFIX = "connection";
private static final String UP_STATUS = "UP";
private ObjectMapper objectMapper = new ObjectMapper();
#Override
public Root deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Map<String, Map<String, Object>> rootJsonMap = parser.readValueAs(Map.class);
boolean isAlive = StringUtils.equals(UP_STATUS, String.valueOf(rootJsonMap.get("status")));
List<Connection> connections = rootJsonMap.entrySet()
.stream()
.filter(entry -> StringUtils.startsWithIgnoreCase(entry.getKey(), CONNECTION_PREFIX))
.map(this::mapToConnection)
.collect(Collectors.toList());
return new Root(isAlive, connections);
}
private PosServerConnection mapToConnection(Map.Entry<String, Map<String, Object>> entry) {
Map<String, Object> connectionJsonMap = entry.getValue();
return objectMapper.convertValue(connectionJsonMap, Connection.class);
}
}
This way i can group all my Connections into one List in Root class.
My question is there any another way to do this ??
I'd like to do this without such big deserializer using just Jackson annotations on my Pojo classes
You can simply achieve this by using #JsonAnySetter annotation for customizing Setter for List<Connection> as follows. You can also reference to Jackson Annotation Examples to see how it works.
POJOs
public class Pojo {
private Root root;
//general getters, setters and toString
}
public class Root {
private String status;
private List<Connection> connections = new ArrayList<>();
public List<Connection> getConnections() {
return connections;
}
#JsonAnySetter
public void setConnections(String name, Connection connection) {
connection.setName(name);
this.connections.add(connection);
}
//other getters, setters and toString
}
public class Connection {
private String name;
private String status;
//general getters, setters and toString
}
Then you can serialize the given JSON string to Pojo with common way by Jackson:
Code Snippet
ObjectMapper mapper = new ObjectMapper();
Pojo pojo = mapper.readValue(jsonStr, Pojo.class);
System.out.println(pojo.getRoot().getConnections().toString());
Console output
[Connection [name=connection1, status=UP], Connection [name=connection2, status=UP]]
Related
in Microservice, we post multiple dtos data as string json.
Controller:
#RequestMapping(value="/json",method = RequestMethod.POST)
public String getjson(#RequestBody String json) {
///Service process
}
Post Json:
{
"dtos":{
"Dto1":{
"name":"Dto1 Name Field",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10}
]
},
"Dto2":{
"city":"Newyork",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10},
{"key":"f3","value":10}
]
}
},
"page":1
}
DTO:
public class Dto1{
private String name;
}
public class Dto2{
private String city;
}
Dto1 and Dto2 is java DTO object name.
how to convert string json to java objects?
You can create a new DTO that contains all attrs and receive in request:
public class Filter{
private String key;
private int value;
}
public class Dto1{
private String name;
private List<Filter> filter;
}
public class Dto2{
private String city;
private List<Filter> filter;
}
public class Dtos{
public Dto1 dto1;
public Dto2 dto2;
}
public class DtoToReceiveInRequest{
private Dtos dtos;
private int page;
}
Controller
#PostMapping
public String getjson(#RequestBody DtoToReceiveInRequest json) {
///Service process
}
You can use the ObjectMapper from the jackson library, like below.
String json = "";
ObjectMapper objectMapper = new ObjectMapper();
Dto1 dto = objectMapper.readValue(json, Dto1.class);
But in your particular example, you don't have to have two DTO classes. You can encapsulate values in one DTO and have the list of different instances of that DTO in a json format.
NB. The json string should be a representation of the preferred class you want to retrieve, eg Dto1.java.
I have a structure that looks like this for RechargeResponse Model:
public class RechargeResponse {
private String code;
private String status;
private Set<OperatorWiseCircles> payload;
// setter and getters
}
here is the OperatorWiseCircles Model
public class OperatorWiseCircles {
private String operatorName;
private String operatorId;
private List<CircleWisePlan> circleWisePlanLists;
//setter and getters
}
CircleWisePlan Model class
public class CircleWisePlan {
private String circleName;
private String circleId;
}
Below is the sample json which we need to flattern.
{
"code": 200,
"status": "SUCCESS",
"payload": [
{
"operatorName": "VODAFONE",
"operatorId": "VF",
"circleWisePlanLists": [
{
"circleName": "C1",
"circleId": "1"
},
{
"circleName": "C2",
"circleId": "2"
}
]
}
]
}
I am expecting this to be flattern and map it to Entity object, so that I can add all these iteration to Hashset and save them all to DB, I want to do it using java8 stream. I how can I do it efficiently. I didnt get the right example, to parse nested json values and create entities for it using map/ flatmap.
Result should be like
Eg: ["VODAFONE","VF","C1", "1"]--->
ENTRY1
["VODAFONE","VF","C2", "2"] ---> ENTRY2
#Entity
public class RechargePlanEntity extends Audit<String>{
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="operator_name")
private String operatorName;
#Column(name="operator_id")
private String operatorId;
#Column(name="circle_name")
private String circleName;
#Column(name="circle_id")
private String circleId;
}
Truth is I'm sure is there any easy way to do this, Yet you can follow something like this,
Here in this example I have created utility class to map OperatorWiseCircles class to List<RechargePlanEntity>.
public class Main {
public static void main(String[] args) throws IOException {
String s = "{\"code\":200,\"status\":\"SUCCESS\",\"payload\":[{\"operatorName\":\"VODAFONE\",\"operatorId\":\"VF\",\"circleWisePlanLists\":[{\"circleName\":\"C1\",\"circleId\":\"1\"},{\"circleName\":\"C2\",\"circleId\":\"2\"}]}]}";
ObjectMapper om = new ObjectMapper();
RechargeResponse response = om.readValue(s, RechargeResponse.class);
List<RechargePlanEntity> collection = response.getPayload()
.stream()
.map(MapUtil::toEntity)
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(collection);
}
}
#Getter
#Setter
#ToString
class RechargePlanEntity {
private Long id;
private String operatorName;
private String operatorId;
private String circleName;
private String circleId;
}
#Getter
#Setter
class RechargeResponse {
private String code;
private String status;
private Set<OperatorWiseCircles> payload;
}
#Getter
#Setter
class OperatorWiseCircles {
private String operatorName;
private String operatorId;
private List<CircleWisePlan> circleWisePlanLists;
}
#Getter
#Setter
class CircleWisePlan {
private String circleName;
private String circleId;
}
final class MapUtil {
public static List<RechargePlanEntity> toEntity(OperatorWiseCircles in) {
return in.getCircleWisePlanLists()
.stream()
.map(MapUtil::map)
.peek(out -> map(in, out))
.collect(Collectors.toList());
}
private static RechargePlanEntity map(CircleWisePlan in) {
RechargePlanEntity out = new RechargePlanEntity();
out.setCircleId(in.getCircleId());
out.setCircleName(in.getCircleName());
return out;
}
private static void map(OperatorWiseCircles in, RechargePlanEntity out) {
out.setOperatorId(in.getOperatorId());
out.setOperatorName(in.getOperatorName());
}
}
The entities without ids may be created from RechargeResponse model providing that the entity has all-args constructor:
RechargeResponse modelFromJson = ... //
List<RechargePlanEntity> entities = modelFromJson.getPayload()
.stream() // Stream<OperatorWiseCircles>
.flatMap(ows -> ows.getCircleWisePlanLists()
.stream() // Stream<CircleWisePlan>
.map(cwp -> new RechargePlanEntity(
null, // instead of id
ows.getOperatorName(),
ows.getOperatorId(),
cwp.getCircleName(),
cwp.getCircleId()
)) // Stream<RechargePlanEntity>
) // Stream<RechargePlanEntity>
.collect(Collectors.toList());
or, if a builder is implemented in the entity class (e.g. using Lombok's #Builder annotation), this conversion may look as follows:
List<RechargePlanEntity> entities = modelFromJson.getPayload()
.stream() // Stream<OperatorWiseCircles>
.flatMap(ows -> ows.getCircleWisePlanLists()
.stream() // Stream<CircleWisePlan>
.map(cwp -> RechargePlanEntity.builder()
.operatorName(ows.getOperatorName())
.operatorId(ows.getOperatorId())
.circleName(cwp.getCircleName())
.circleId(cwp.getCircleId())
.build()
) // Stream<RechargePlanEntity>
) // Stream<RechargePlanEntity>
.collect(Collectors.toList());
I want to create below JSON payload
{
"maxResults":3,
"counter":0,
"customerParameters":{
"filters":[
{
"name":"customerId",
"operator":"=",
"value":["hello"]
}
]
},
"dealerParameters":[
{
"name":"club"
},
{
"name":"token"
}
]
}
Coded so far:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"maxResults",
"counter",
"customerParameters",
"dealerParameters"
})
public class CustomerModel {
#JsonProperty("maxResults")
private Integer maxResults;
#JsonProperty("counter")
private Integer counter;
#JsonProperty("customerParameters")
private CustomerParameters customerParameters;
#JsonProperty("dealerParameters")
private List<DealerParameter> dealerParameters = null;
#JsonProperty("customerParameters")
public CustomerParameters getCustomerParameters() {
return customerParameters;
}
#JsonProperty("customerParameters")
public void setCustomerParameters(CustomerParameters customerParameters) {
this.customerParameters = customerParameters;
}
#JsonProperty("dealerParameters")
public List<DealerParameter> getDealerParameters() {
return dealerParameters;
}
#JsonProperty("dealerParameters")
public void setDealerParameters(List<DealerParameter> dealerParameters) {
this.dealerParameters = dealerParameters;
}
// Getter/Setter for other params
}
CustomerParameters.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"filters"
})
public class CustomerParameters {
#JsonProperty("filters")
private List<Filter> filters = null;
// Setter and Getter for filters parameter
}
DealerParameters.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"name"
})
public class DealerParameter {
#JsonProperty("name")
private String name;
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("name")
public void setName(String name) {
this.name = name;
}
}
Filter.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"name",
"operator",
"value"
})
public class Filter {
#JsonProperty("name")
private String name;
#JsonProperty("operator")
private String operator;
#JsonProperty("value")
private List<String> value = null;
#JsonProperty("value")
public List<String> getValue() {
return value;
}
#JsonProperty("value")
public void setValue(List<String> value) {
this.value = value;
}
// Setter and Getter for other properties
}
Missing Part:
#Controller
public class TestContoller {
RestTemplate restTemplate;
Should I instantiate each pojo class with new operator as below and set all required parameters ? or any other approach of creating JSON payload?
CustomerModel customerModel= new CustomerModel();
customerModel.setMaxResults(1);
Filter filter= new Filter();
filter.setName("customerID");
filter.setOperator("-");
filter.setValue(Arrays.asList("club"));
CustomerParameters customerParameters = new CustomerParameters();
customerParameters.setFilters(Arrays.asList(filter));
customerModel.setCustomerParameters(customerParameters);
For DealerParameter class, I want to create multiple objects with same key different value(see the json payload I mentioned above). Below code creates only one object "name":"dealerId"
DealerParameter dealerParameter = new DealerParameter();
dealerParameter.setName("dealerId");
customerModel.setDealerParameters(dealerParameter);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValueAsString(customerModel);
restTemplate.exchange(todo); // restful service call
}
you are already using "ObjectMapper", And ObjectMapper has readValue() method. By using readValue() method you can populate all data at a time like below:--
ObjectMapper objectMapper = new ObjectMapper();
//populating data from json string to POJO
CustomerModel customerModel = objectMapper.readValue(<json String>,CustomerModel.class);
System.out.println(objectMapper.writeValueAsString(customerModel); // print all data
I would like to deserialize JSON of this structure:
{
"employee_pricing_type":"COMPUTE_BY_OWN_RATE",
"employee_rate":10,
"customer_pricing_type":"COMPUTE_BY_OWN_RATE",
"customer_rate":200
}
I have such POJO to create price setting from a HTTP request:
public class ObjectPricingSetting {
#JsonProperty("pricing_type") // describes output
private final ObjectPricingType pricingType;
#JsonProperty("own_rate") // describes output
private final BigDecimal ownRate;
public ObjectPricingSetting(final ObjectPricingType pricingType, final BigDecimal ownRate) {
AssertUtils.notNull(pricingType, "pricingType");
this.pricingType = pricingType;
if (ownRate != null) {
AssertUtils.isGtZero(ownRate, "ownRate");
this.ownRate = ownRate;
} else {
this.ownRate = null;
}
}
public ObjectPricingType getPricingType() {
return pricingType;
}
public BigDecimal getOwnRate() {
return ownRate;
}
}
this is DTO:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonProperty(value = "employee_pricing_setting")
private ObjectPricingSetting employeePricingSetting;
#JsonProperty(value = "customer_pricing_setting")
private ObjectPricingSetting customerPricingSetting;
}
I would like to create these two instances of ObjectPricingSetting with #JsonCreator.
Q: How should I anotate #JsonProperty parameter in ObjectPricingSetting constructor to recognize what JSON value should use to create these two instances?
You can use #JsonUnwrapped with a prefix in your parent class:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonUnwrapped(prefix = "employee_")
private ObjectPricingSetting employeePricingSetting;
#JsonUnwrapped(prefix = "customer_")
private ObjectPricingSetting customerPricingSetting;
}
Then you can use the normal #JsonCreator/#JsonProperty in your nested DTO, without the prefix:
public class ObjectPricingSetting {
#JsonCreator
public ObjectPricingSetting(
#JsonProperty("pricing_type") final ObjectPricingType pricingType,
#JsonProperty("rate") final BigDecimal ownRate) {
...
I have a response from web service call like this
// other key/values
properties: {
1000:true
2000:false
2939:true
...
}
// other key/values
I want to deserialize it to a POJO List which is
public class Service implements Serializable {
private Integer id;
private Boolean readOnly;
...
}
So far i have tried
ObjectMapper mapper = new ObjectMapper();
user.setServices(mapper.convertValue(response.getProperties(), Service.class));
But it doesn't convert map directly to the List. How do i achieve this? Here are the details:
Where response.getProperties() returns
#JsonAnyGetter
public Map<Integer, Boolean> getProperties() {
return properties;
}
And user.setServices
public void setServices(List<Service> services) {
this.services = services;
}