I have a json object which looks something like this
"price": {
"sale": {
"value": 39.99,
"label": "Now"
},
"regular": {
"value": 69.5,
"label": "Orig."
},
"shippingfee": 0,
"pricetype": "Markdown",
"pricetypeid": 7,
"onsale": true
}
"sale" and "regular" are keywords (unique) are 2 of the many price-types available, and the labels
"Orig" and "Now" are keywords (unique) are 2 of the many labels available.
I am not sure the best data structure to store this price json into the POJO.
can someone please guide me through this ?
I guess your problem is to convert the sale and regular attributes into an uniform representation which probably could use an Enumeration for the unique values. With default mechanism of JSON serilization/deserialization, this could be difficult. I am not sure about the JSON parsing library you are using, in Jackson there is a possibility to register custom serializers and deserializers for fields (using annotations). In this case, whcy tou would do is to register a custom serializer/deserializer and handle the fields of the JSON in the way you want it. You could refer this post
Added the below in response to the comment:
A probable dtructure for the POJO could be as below:
publi class Price{
protected List<PricePointDetails> pricePointDetails;
protected float shippingFee;
protected PriceTypes priceType;
protected priceTypeId;
protected boolean onSale;
}//class closing
public class PricePointDetails{
protected PriceTypes priceType;
protected float value;
protected LabelTypes labelType;
}//class closing
public enumeration PriceTypes{
sale,regular,markdown;
}//enumeration closing
public enumeration LabelTypes{
Orig,Now;
}//enumeration closing
What I have added, is just one way of structuring the data, it could be done in otherways also.
Related
I am learning SpringBoot and am doing this coding challenge. So far, I have successfully set up the controller and have done the mapping.
#RestController
#RequestMapping(path="/mydomain")
public class PaymentController {
#RequestMapping(method=RequestMethod.POST, value="/ingest")
public void ingestData(#RequestBody String data) {
System.out.println("ingest Data");
System.out.println(data);
// List<Orders>
// List<Returns>
}
#RequestMapping(method=RequestMethod.GET, value="/query")
public String queryData(#RequestBody String data) {
// look at LIST of order and return..and return something
}
}
The String data is JSON and it contains two different types - Order and Return.
{
"entries": {
{
type: "ORDER",
name: "order_1",
"attributes": {
"owner": "John"
}
},
{
type: "ORDER",
name: "order_2",
"attributes": {
"owner": "Mike",
"buyer": "Bob"
}
// attributes is a key/value pair Map
},
{
type: "RETURN",
name: "return_1",
"attributes": {
"user": "kelly",
"time": "null",
"inputs": [
"USD",
"EUR"
],
"outputs": [
"CAD",
"GBP"
]
}
// attributes is a key/value pair Map
},
}
}
In ingestData(), I want to parse though the json and create 2 lists - one each for orders and returns. In the past, I have dealt with the all the items in the json mapping to the same Java class. How do I parse and map json items into 2 different java classes?
You should probably rethink your REST api setup a bit. It's better to create endpoints based on classes rather than have generic endpoints that process multiple. Although this might look like more work now it will really help you generate more maintainable code. The fact that you now run into this problem where you want an ObjectMapper to resolve to different classes from a single Json is a good indicator that you're going in the wrong direction.
There is a great REST API design best-practices here on Stack available
[JsonString] -some json parsing libraries-> [Collection<Entity>] -.stream().collect(Collectors.groupingBy())-> [Map<String(type),Collection<Entity>>]
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
This is the Java enum that I want to transform into an Avro Schema:
public enum ApplicationCode {
APP_A("MY-APP-A"),
APP_B("MY-APP-B");
private final String code;
ApplicationCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
Since enums are generally available as Types in Avro, I came up with following:
{
"type" : "enum",
"name" : "ApplicationCode",
"namespace" : "com.example",
"symbols" : [ "APP_A", "APP_B" ]
}
And referenced it in my main Avro like this:
"fields": [
{
"name": "masterApplicationCode",
"type": "ApplicationCode"
},
It works like that but unfortunately I am losing the Application Codes (e.g. "MY-APP-A") using this approach. I'm looking for something, that allows me to include both, the code and the label. Something like
{
"type" : "enum",
"name" : "ApplicationCode",
"namespace" : "com.example",
"symbols" : [ "APP_A("MY-APP-A")", "APP_B("MY-APP-B")" ]
}
Is it even possible to have this kind of complex enums or is there any workaround to achieve this?
I believe the avro schema is internally transforming it into a JSON String. So, I think the question is more about serializing enums. Reference from here - https://www.baeldung.com/jackson-serialize-enums
I think it should return the code if you use JsonFormat annotation like this -
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ApplicationCode {
Otherwise you will need to add a Custom Serializer for enum.
I solved my problem by writing custom serializer / deserializer that map an object with complex typed fields to one that is being sent with e.g. Strings instead of enums.
Here an example of the custom serializer:
public class CustomSerializer implements Serializer<ApplicationObject> {
#Override
public byte[] serialize(String topic, ApplicationObject ApplicationObjectDto) {
com.example.avro.ApplicationObject applicationObject = com.example.avro.ApplicationObject.newBuilder()
.setApplicationCode(ApplicationObjectDto.getApplicationCode().getCode())
.build();
return SerializationUtils.serialize(applicationObject);
}
}
I have a class with some field
public class SomeClass {
private Duration discussionTime;
}
When i try to send this class to frontend using #RestController in Spring, i see that answer:
"discussionTime": {
"seconds": 7,
"zero": false,
"negative": false,
"nano": 72000000,
"units": [
"SECONDS",
"NANOS"
]
}
Is there ways to set format of answer to
"discussionTime": 7 ?
There are two ways you can do this:
custom mapping to a new object (instead of returning a Duration)
by creating your own serializer: serialize/deserialize java 8 java.time with Jackson JSON mapper
But if you only want the seconds, might be best to just create a new object you serialize instead of messing with the Duration.
An option could be to use a MixIn.
Also JavaTimeModule could help you.
Depending on your use case you can create your own serializer as suggested by others or go for a more generic solution if you have to do this in multiple places.
Or maybe:
public class SomeClass {
private Duration discussionTime;
#JsonProperty("discussionTime")
public long getDiscussionTimeSeconds() {
return discussionTime.getSeconds();
}
}
I would like to create a POJO that wouldn't need to change when adding new fields to its JSON representation.
It would have some basic and required fields but will store any new fields that will be added in the future.
Examples of JSON:
{
"id": 12345,
"name":"udy",
"text": "hi, my name is udy",
"data": { "gender": "male, "age": 65, "location":{"city":"nyc"} }
}
I thought about creating this POJO:
public class Pojo{
private long id;
private String name;
private String text;
private Map data;
}
But I'm not sure this is the best option.
Couple of things in head are:
Fast serialize/deserialize to json (boon)
Flexible support for different types (lists, objects) in data field
I know that jackson can handle unknown fields, however it is pretty slow comparing to boon
I have code in my android project that correctly deserializes json into POJO's using gson. I wish to add some condtional acceptance checks (sanity checks) to the incoming json. For instance, with the data structure below, I wish for the gson parser to only add objects where the start date < end date. I know I could iterate through the list after it is populated to remove invalid items, but I was wondering if there was any way to reject the items on the fly. Any help would be appreciated.
Example JSON
{
"Items" : [
{
"Name" : "Example Name",
"Start" : "2010-10-16 10:00:00",
"End" : "2011-03-20 17:00:00",
<other fields>
},
<several more items>
]
}
ItemList.java
public class ItemList {
private List<ItemHeader> Items;
public void setItemHeaders(List<ItemHeader> headers) {
Items = headers;
}
public List<ItemHeader> getItemHeaders() {
return Items;
}
}
ItemHeader.java has fields for name, start, end and all the other fields.
You'd need to write your own deserializer and have it throw an exception when your condition isn't met.
http://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer
I don't know that you should do this, but it's possible.