Currently service response looks like this:
{
"values": [
{
"field1": "value",
.................
},
{
"field1": "value",
.................
}
]
metadata1:[],
metadata2:"-"
}
But just want to send array of values as response. Like this
[
{
"field1": "value",
.................
},
{
"field1": "value",
................
}
]
I am able to suppress metadata info with the help of #JsonIgnoreProperties. But response still like this:
{
"values": [
{
"field1": "value",
.................
},
{
"field1": "value",
.................
}
]
}
How can I fix it?
It is easy to achieve using the #JsonValue annotation which can change the representation of the of your java class. Just add a method annotated with this annotation to your response class that returns the values collection. Here is an example:
public class JacksonValue {
public static class Bean {
private final List<String> values;
public Bean(List<String> values) {
this.values = values;
}
#JsonValue
public List<String> getValues() {
return values;
}
}
public static void main(String[] args) throws JsonProcessingException {
Bean bean = new Bean(Arrays.asList("a", "b", "c"));
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(bean));
}
}
Output:
["a","b","c"]
Related
{
"DistributionOrderId" : "Dist_id_1",
"oLPN":
{
"Allocation":
{
"AID": "12345"
},
"Allocation":
{
"AID": "123456" ,
"SerialNbr": "SRL001",
"BatchNbr": "LOT001"
"RevisionNbr": "RVNBR1"
}
},
"oLPN":
{
"Allocation":
{
"AID": "12123"
}
"Allocation":
{
"AID": "12124"
}
}
}
I have a JSON request passed from the vendor, How to store the values as Java POJO and use them further?
Edit : Added attributes to JSON
As you aren't using the usual camel case conventions common in jackson databinding I would suggest defining a java object with the appropriate annotations. The object is not currently valid json. If for example the json looks like this:
{
"DistributionOrderId" : "Dist_id_1",
"oLPN": [ ... ]
}
Where each oLPN in the array is an object like this:
{
"Allocation": [{ "AID": ... }, { "AID": ... }, ... ]
}
You can write a class for distribution orders
public class DistributionOrder {
#JsonProperty("DistributionOrderId") private String id;
#JsonProperty("oLPN") private List<OLPN> olpn;
// getters and setters
}
Then another for the OLPN object
public class OLPN {
#JsonProperty("Allocation") private String allocation;
#JsonProperty("AID") private String aid;
// getters and setters
}
Then you can use an object mapper as appropriate. For example
ObjectMapper mapper = ... // get your object mapper from somewhere
DistributionOrder distributionOrder = mapper.readValue(raw, DistributionOrder.class);
See also object mapper javadoc
json key can't repeat, and the repeat key with value will be discard.
i have format your json text, may be it is like following expression:
{
"DistributionOrderId" : "Dist_id_1",
"oLPN":
[
{
"Allocation":
[
{
"AID": "123456" ,
"SerialNbr": "SRL001",
"BatchNbr": "LOT001",
"RevisionNbr": "RVNBR1"
},
{
"AID": "12345"
}
]
},
{
"Allocation":
[
{
"AID": "12123"
},
{
"AID": "12124"
}
]
}
]
}
and this struct match the java object is
class DistributionOrder{
#JsonProperty("DistributionOrderId")
String distributionOrderId;
List<OLPN> oLPN;
}
class OLPN {
#JsonProperty("Allocation")
List<Allocation> allocation;
}
class Allocation{
String AID;
#JsonProperty("SerialNbr")
String serialNbr;
#JsonProperty("BatchNbr")
String batchNbr;
#JsonProperty("RevisionNbr")
String revisionNbr;
}
Say I have to compose below JSON string response to a HTTP get request:
{
"filename": "100055_1_0920_082714_014",
"sfyc": "1",
"rect": [
{"type1": ["1145", "1027", "1954", "1259"]},
{"type2": ["1527", "788", "569", "418"]},
{"type1": ["4053", "773", "915", "449"]}
]
}
I think if I want to compose the JSON string, I need a JSON Object({"type1": ["1145", "1027", "1954", "1259"]}),wihch can be transformed from a Java Class which has a feild type1 of type List<String>, and another Class for type2. Then Gson or Jackson can help in my case.
Problem is that I have more than 20 different types, so I don't think defining all of these Java classes is a good choice. So how can I have the wanted JSON String in a smart way?
Note:
Each type may appear more than once(like type1 in my code) so map should not be the answer.
You may use a dto like
public class Dto {
private String fileName;
private Integer sfyc;
private List<Map<String, List<String>>> rect;
}
Try running the main method to verify
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
public class Test {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Dto dto = getDummy();
System.out.println(mapper.writeValueAsString(dto));
}
#Data
public static class Dto {
private String fileName;
private Integer sfyc;
private List<Map<String, List<String>>> rect;
}
public static Dto getDummy() {
Dto dto = new Dto();
dto.setFileName("100055_1_0920_082714_014");
dto.setSfyc(1);
List<String> type1List = List.of("1145", "1027", "1954", "1259");// of function for java 9 or newer
List<String> type2List = List.of("1527", "788", "569", "418");
List<String> type3List = List.of("4053", "773", "915", "449");
List<Map<String, List<String>>> maps =
List.of(
Map.of("type1", type1List),
Map.of("type2", type2List),
Map.of("type1", type3List));
dto.setRect(maps);
return dto;
}
}
it will produce an out put like
{
"fileName": "100055_1_0920_082714_014",
"sfyc": 1,
"rect": [
{
"type1": [
"1145",
"1027",
"1954",
"1259"
]
},
{
"type2": [
"1527",
"788",
"569",
"418"
]
},
{
"type1": [
"4053",
"773",
"915",
"449"
]
}
]
}
I think the solution for this, is to use a map to store the custom types, So that we don't have to create a new class for each type. I was able to achieve this using following code.
POJO class.
public class Example {
#JsonProperty("filename")
private String filename;
#JsonProperty("sfyc")
private String sfyc;
#JsonProperty("rect")
private List<Map<String,List<String>>> rect;
#JsonProperty("filename")
public String getFilename() {
return filename;
}
#JsonProperty("filename")
public void setFilename(String filename) {
this.filename = filename;
}
#JsonProperty("sfyc")
public String getSfyc() {
return sfyc;
}
#JsonProperty("sfyc")
public void setSfyc(String sfyc) {
this.sfyc = sfyc;
}
/**
* #return the list
*/
#JsonProperty("rect")
public List<Map<String, List<String>>> getList() {
return rect;
}
/**
* #param list the list to set
*/
#JsonProperty("list")
public void setList(List<Map<String, List<String>>> rect) {
this.rect = rect;
}
}
Main class to test this change.
public class TestJsonProblem {
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
Example example = new Example();
example.setFilename("Test");
example.setSfyc("1");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("type1", Arrays.asList("1145", "1027", "1954", "1259"));
map.put("type2", Arrays.asList("1145", "1027", "1954", "1259"));
map.put("type3", Arrays.asList("1145", "1027", "1954", "1259"));
List<Map<String, List<String>>> list = new ArrayList();
list.add(map);
example.setRect(list);
ObjectMapper mapper = new ObjectMapper();
String jsonData = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(example);
System.out.println(jsonData);
}
}
Output :
{
"filename" : "Test",
"sfyc" : "1",
"rect" : [ {
"type3" : [ "1145", "1027", "1954", "1259" ],
"type2" : [ "1145", "1027", "1954", "1259" ],
"type1" : [ "1145", "1027", "1954", "1259" ]
} ]
}
{
"filename": "100055_1_0920_082714_014",
"sfyc": "1",
"rect": [
{
"type1": [
"1145",
"1027",
"1954",
"1259"
]
},
{
"type2": [
"1527",
"788",
"569",
"418"
]
},
{
"type3": [
"4053",
"773",
"915",
"449"
]
}
]
}
and use this as Web site
http://www.jsonschema2pojo.org/
i would like to know if rest api while consuming input parameter can do the following:
let's say my json object have the following parameters:
string name;
string adress;
hashmap<string,object> content;
and here's an exemple of what can be sent:
{
"name": "AZ",
"adress": "US",
"content": {
"clients": [
{
"client_ref":"213",
"commands" : {
"subCommands": [
{
"num":"1",
"price":"10euro"
},
{
"num":"12,
"price":"10euro"
}
]
}
},
{
"client_ref":"213",
"commands" : {
"subCommands": [
{
"num":"1",
"price":"10euro"
},
{
"num":"12,
"price":"10euro"
}
]
}
}
]
}
}
the question is can rest build the hashmap where the object can itself have n child of hashmap type ... ?
(i'm using jersey as rest implementation )
Assuming that you have a JSON provider such as Jackson registered and your model class looks like:
public class Foo {
private String name;
private String address;
private Map<String, Object> content;
// Getters and setters
}
The following resource method:
#Path("foo")
public class Test {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response post(Foo foo) {
...
}
}
Can handle a request like:
POST /api/foo HTTP/1.1
Host: example.org
Content-Type: application/json
{
"name": "AZ",
"adress": "US",
"content": {
"clients": [
{
"client_ref": "213",
"commands": {
"subCommands": [...]
}
},
{
"client_ref": "213",
"commands": {
"subCommands": [...]
}
}
]
}
}
content is an Object, not a map.
"content": {
"clients": [
{
"client_ref":"213",
"commands" : {
"subCommands": [
{
"num":"1",
"price":"10euro"
},
{
"num":"12,
"price":"10euro"
}
]
}
},
{
"client_ref":"213",
"commands" : {
"subCommands": [
{
"num":"1",
"price":"10euro"
},
{
"num":"12,
"price":"10euro"
}
]
}
}
]
}
And this is Java Object presentation.
public class Content {
private List<Client> clients;
//Getters and setters
}
public class Client {
private String clientRef;
private List<Command> commands;
//Getters and setters
}
//And so on, define other classes.
To answer your question, yes, you can build a map.
Check this example, please. It tells how to parse an unknown json (in case you don't know the exact structure of your json object).
https://stackoverflow.com/a/44331104/4587961
Then you can build a map with fields
Map<String, Object> where some values of this map will be nested maps.
you can use javax.ws.rs.core.GenericEntity to wrap collections with generic types (your HashMap).
#GET
#Path("/mapping")
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getAllMapContents() {
Map<String,Object> map = new HashMap<String,Object>();
map.put("Hello", "World");
map.put("employee", new Employee(1,"nomad"));
GenericEntity<Map<String,Object>> entity = new GenericEntity<Map<String,Object>>(map) {};
return Response.ok(entity).build();
}
I checked it and found it working Please find the response below. Thank you.
{
"Hello": "World",
"employee": {
"id": 1,
"name": "nomad"
}
}
{"myContainer" :
{ "couldBeAnything" : [
{"id":1, "name":"sb", "category":"couldBeAnything"},
{"id":2, "name":"bs", "category":"couldBeAnything"}
],
"somethingElse" : [
{"id":1, "name":"sdsa","category":"somethingElse"},
{"id":2, "name":"ve","category":"somethingElse"}
]
},
"id" : 0
}
So far I have :
Type myContainerType = new TypeToken<MyContainer>(){}.getType();
MyContainerType myContainerType = gson.fromJson(myJson.getValue(), myContainerType);
Where
public class MyContainer {
private int id;
private Map<String, List<Foo>> foo; // and foo has id, name, category
The result, no errors, a populated id field, but just a null map
I think the json is wrong for the structure Map<String, List<Foo>>. When you say map you need not enclose each key-value with {. Just put the whole key values in one {} and seprate with commas. eg
{
"myContainer": {
"couldBeAnything": [
{
"id": 1,
"name": "sb",
"category": "couldBeAnything"
},
{
"id": 2,
"name": "bs",
"category": "couldBeAnything"
}
],
"somethingElse": [
{
"id": 1,
"name": "sdsa",
"category": "somethingElse"
},
{
"id": 2,
"name": "ve",
"category": "somethingElse"
}
]
},
"id": 0
}
With this json it works perfectly
public static void main(String[] args){
String json = "{\"myContainer\":{\"couldBeAnything\":[{\"id\":1,\"name\":\"sb\",\"category\":\"couldBeAnything\"},{\"id\":2,\"name\":\"bs\",\"category\":\"couldBeAnything\"}],\"somethingElse\":[{\"id\":1,\"name\":\"sdsa\",\"category\":\"somethingElse\"},{\"id\":2,\"name\":\"ve\",\"category\":\"somethingElse\"}]},\"id\":0}";
Map<String, List<Foo>> obj = new HashMap<String, List<Foo>>();
Gson gson = new Gson();
obj = gson.fromJson(json, obj.getClass());
System.out.println(obj);
}
Output
{id=0.0, myContainer={couldBeAnything=[{id=1.0, name=sb, category=couldBeAnything}, {id=2.0, name=bs, category=couldBeAnything}], somethingElse=[{id=1.0, name=sdsa, category=somethingElse}, {id=2.0, name=ve, category=somethingElse}]}}
The issue with your approach was the naming of the field foo. Your json contains the Map<String, List<Foo>> name as myContainer. So modify your container class like below and it will work fine :)
public class MyContainer {
private int id;
private Map<String, List<Foo>> myContainer;
}
Now this will work
Type myContainerType = new TypeToken<MyContainer>(){}.getType();
MyContainer myContainer = gson.fromJson(json, myContainerType);
System.out.println(myContainer);
I am parsing JSON and am having difficulty with one structure that can have one of three forms. In my case it could be zero-dimensional, one-dimensional or two-dimensional. Is there some way I can inspect the JSON on the fly to determine which one it is? Or perhaps consume it anyway and work out what it is afterwards.
The structures look like this and can be embedded in other structures.
"details":{
"Product":"A zero-dimensional Product"
},
"details":{
"Product":"A one-dimensional Product",
"Dimensions": [ "Size" ],
"Labels": [ "XS", "S", "M", "L" ]
},
"details":{
"Product":"A two-dimensional Product",
"Dimensions": [ "Size", "Fit" ],
"Labels": [[ "XS", "S", "M", "L" ],[ "26", "28", "30", "32" ]]
}
What I may be looking for is a generic class that Jackson will always match with.
Something like translating:
{
"SomeField": "SomeValue",
...
"details":{
...
}
}
Into:
class MyClass {
String SomeField;
...
AClass details;
}
Is there a class AClass I can define that could be a universal recipient for any JSON structure or array?
Thanks to Eric's comment pointing me to programmerbruce I managed to crack it. Here's the code I used (cut down to simplify).
public static class Info {
#JsonProperty("Product")
public String product;
// Empty in the 0d version, One entry in the 1d version, two entries in the 2d version.
#JsonProperty("Dimensions")
public String[] dimensions;
}
public static class Info0d extends Info {
}
public static class Info1d extends Info {
#JsonProperty("Labels")
public String[] labels;
}
public static class Info2d extends Info {
#JsonProperty("Labels")
public String[][] labels;
}
public static class InfoDeserializer extends StdDeserializer<Info> {
public InfoDeserializer() {
super(Info.class);
}
#Override
public Info deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Class<? extends Info> variantInfoClass = null;
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
// Inspect the `diemnsions` field to decide what to expect.
JsonNode dimensions = root.get("Dimensions");
if ( dimensions == null ) {
variantInfoClass = Info0d.class;
} else {
switch ( dimensions.size() ) {
case 1:
variantInfoClass = Info1d.class;
break;
case 2:
variantInfoClass = Info2d.class;
break;
}
}
if (variantInfoClass == null) {
return null;
}
return mapper.readValue(root, variantInfoClass);
}
}
And to install this in the ObjectMapper:
// Register the special deserializer.
InfoDeserializer deserializer = new InfoDeserializer();
SimpleModule module = new SimpleModule("PolymorphicInfoDeserializerModule", new Version(1, 0, 0, null));
module.addDeserializer(Info.class, deserializer);
mapper.registerModule(module);
factory = new JsonFactory(mapper);
Is this structure what you want for AClass?
class Dimension {
String name;
List<String> possibleValues;
}
class Product {
String name;
List<Dimension> dimensions;
}
All you need to do is change the length of the dimensions list to account for the three types.
Parsing becomes a trivial problem of checking if the Dimensions property is present in the JSON, and if so, iterating over it and appending to the dimensions list.
Another idea would be to restructure the JSON (if you can) such that all cases are of the same form:
"d0":{
"Product":"A zero-dimensional Product",
"Dimensions": {}
},
"d1":{
"Product":"A one-dimensional Product",
"Dimensions": {
"Size": [ "XS", "S", "M", "L" ]
}
},
"d2":{
"Product":"A two-dimensional Product",
"Dimensions": {
"Size": [ "XS", "S", "M", "L" ],
"Fit": [ "26", "28", "30", "32" ]
}
}