I am very new to java and just started with json...
I have the following json file:
"step1": {
"version": 1,
"items": {
"run": false,
"jump": true
}
},
"step2": {
"version": "None",
"items": {
"happy": true,
"sad": false
}
}
I am using Gson in my main like this:
Gson gs = new Gson();
Content tmp = gs.fromJson(<json string>, Content.class);
my class:
public class Content {
#SerializedName("step1")
private Step step1;
#SerializedName("step2")
private Step step2;
}
each step class:
public class Step{
#SerializedName("version")
private String version;
#SerializedName("items")
???????
}
as you can see the "?????" part is what I am trying to understand - How can I convert the items without needing to know the field name..? meaning to a HashMap/another iterable object..? can I initialize using a method..?
I have tried creating an Item class with a constructor but I do not understand how to use it in this case..
The solution that worked for me is:
public class Step{
#SerializedName("version")
private String version;
#SerializedName("items")
private HashMap<String,Boolean> items;
}
You can use a Map<String, Boolean> to store your items. You Step class can be something, like this:
public class Step {
private String version;
private Map<String, Boolean> items;
}
Then you can add your values to the Map:
Step step = new Step();
step.setVersion("None");
Map<String, Boolean> items = new HashMap<>();
items.put("happy", Boolean.TRUE);
items.put("sad", Boolean.FALSE);
step.setItems(items);
Hope that helps you.
Related
stucked at accessing nested json. similar stuff:
[
{
key-value,
key-value
},
{
key-value,
key-value
},
{
key-value,
key-value
}
]
works nicely but when i try:
{
"alfa":{
"id":"foo",
"product":{
"id":"foo1",
"price":"foo2"
}
},
"beta":{
"id":"foo",
"product":{
"id":"foo1",
"price":"foo2"
}
}
}
i get error:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<...
i of course did change structure of classes:
public class Alphabet{
private Purchase purchase;
...
public class Purchase{
private String id;
private Product product;
...
public class Product {
private String id;
private String price;
...
to read it:
ObjectMapper mapper = new ObjectMapper();
InputStream inputStream = new FileInputStream(new File("src/main/json/file.json"));
TypeReference<List<Alphabet>> typeReference = new TypeReference<List<Alphabet>>() {};
List<Alphabet> alphabet= mapper.readValue(inputStream, typeReference);
System.out.println(alphabet);
whats wrong, please?
It seems like the JSON structure you try to read is not a List<Alphabet>, but a Map<String, Purchase>.
Your second json not like list of object. The second json look lik have 2 main objects if so you need class like below.
public class Alphabet{
private Purchase purchase;
private Purchase purchase1;
}
But it not good practice. Use as first josn like list of objects.
The difficulty is, that the json labels are partly dynamic in the rest response of the Kraken api. At first I introduce a working case. I connect the Kraken trading api to fetch currencies as assets and got the following result in json.
{
"error": [],
"result": {
"AAVE": {
"aclass": "currency",
"altname": "AAVE",
"decimals": 10,
"display_decimals": 5
},
"ZUSD": {
"aclass": "currency",
"altname": "USD",
"decimals": 4,
"display_decimals": 2
}
}
}
AAVA and ZUSD in this example are dynamic labels. I use the embedded Jackson to parse it in the OpenFeign framework. The result part are covered with the following generic class:
public class Response<T> {
private List<String> error = new ArrayList<>();
private T result;
// getter and setters
}
And as root class for the assets, the dynamic labels AAVA and ZUSD are handled by a Map:
public class AssetInfoResponse extends
Response<Map<String, AssetInfo>> {
}
The pojo AssetInfo:
public class AssetInfo implements Serializable{
#JsonProperty("altname")
private String alternateName;
#JsonProperty("aclass")
private String assetClass;
#JsonProperty("decimals")
private Byte decimals;
#JsonProperty("display_decimals")
private Byte displayDecimals;
// getters, setters ...
}
The above case works perfectly, also the solution with the dynamic labels.
Here is the response with the ohlc data, that looks similar and I have no Idea to solve the deserialization problem in the next case:
{
"error": [],
"result": {
"XXBTZEUR": [
[
1613212500,
"39000.1",
"39010.1",
"38972.3",
"38994.1",
"38998.1",
"3.23811638",
70
],
[
1613212560,
"38994.3",
"39014.5",
"38994.3",
"39014.5",
"38997.3",
"0.95105956",
11
]
],
"last": 1613212500
}
}
The cause of the problem is the "last": 1613212500 property line. When I remove this line, the response can be parsed without problems. I try to solve it with the following classes, Response is the upper described class.
public class OhlcLastResponse<T> extends Response<T> {
private Long last;
// getters and setters
}
The next class extends the prevourious class and is the root class for the objectmapper:
public class OhlcResponse
extends OhlcLastResponse<Map<String, List<Candelstick>>> {
}
And the pojo that holds the candlestick data:
#JsonFormat(shape = JsonFormat.Shape.ARRAY)
#JsonPropertyOrder({ "time", "open", "high", "low",
"close", "vwap", "volume", "count" })
public class Candelstick implements Serializable {
private Integer time;
private BigDecimal open;
private BigDecimal high;
private BigDecimal low;
private BigDecimal close;
private BigDecimal vwap;
private BigDecimal volume;
private Integer count;
// getters and setters ...
}
and here is the error:
"38997.3",
"0.95105956",
11
]
],
"last": 1613212500
}
}
"; line: 26, column: 11] (through reference chain: OhlcResponse["result"]->java.util.LinkedHashMap["last"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
Jackson tries to put the last property into the map, but the map was finished by ],. Line 26 is the line with the
last label in the json file.
Is there a possibility to parse this json? I think it must be possible, because the array is closed by the square bracket.
I hosted the rest client on github. To reproduce the error just clone it and run mvn test.
The solution is a deserializer, because the type handling is very difficult in this case. The deserializer decide between the two cases, array or the single last value, and call in the case of an array the deserializer for the CandleStick Class:
public class OhlcDeserializer extends JsonDeserializer<OhclPayload> {
#Override
public OhclPayload deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
List<CandleStick> candleSticks = new ArrayList<CandleStick>();
Long last = null;
ObjectCodec objectCodec = p.getCodec();
JsonNode jsonNode = objectCodec.readTree(p);
Iterator<Entry<String, JsonNode>> payloadIterator = jsonNode.fields();
while (payloadIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = payloadIterator.next();
if (entry.getKey().equals("last")) {
last = entry.getValue().asLong();
} else if (entry.getValue().isArray()) {
for (JsonNode node : entry.getValue()) {
CandleStick cs = p.getCodec().treeToValue(node, CandleStick.class);
candleSticks.add(cs);
}
}
}
return new OhclPayload(candleSticks, last);
}
}
I changed the OhclResponse to:
public class OhlcResponse extends Response<OhclPayload> {
}
And insert a OhlcPayload class for the deserializer:
#JsonDeserialize(using = OhlcDeserializer.class)
public class OhclPayload {
private List<CandleStick> candleSticks;
private Long last;
// getters and setters
}
Thats all.
I am trying to convert following JSON to Java object and ending up with UnrecognizedPropertyException.
{
"5214": [{
"name": "sdsds",
"age": "25",
"address": null
},
{
"name": "sdfds",
"age": "26",
"address": null
}]
}
Here "5214" is the random key that I get. I can covert it by modifying JSON little bit. But I want to know whether any possible way to convert the mentioned JSON. I even tried with following snippet taking some reference.
public class SampleTest {
private Map<String, List<EmployeeDetails>> employeeDetails = new HashMap<String, List<EmployeeDetails>>();
public Map<String, List<EmployeeDetails>> getEmployeeDetails() {
return employeeDetails;
}
public void setEmployeeDetails(Map<String, List<EmployeeDetails>> employeeDetails) {
this.employeeDetails = employeeDetails;
}
}
public class EmployeeDetails {
private String name;
private String age;
private String address;
//Getters and Setters
}
Can someone guide me on this?
Use Type Reference (Import Jackson Package for Java)
TypeReference<Map<String, List<EmployeeDetails>>> typeReference = new TypeReference<Map<String, List<EmployeeDetails>>>()
{
};
Map<String, List<EmployeeDetails>> employeeDetails = new ObjectMapper().readValue(jsonString, typeReference);
Check something from that
Maybe:
public class Data {
// String contain the Key, for example: 5214
Map<String, List<EmployeeDetails>> employeeDetails =
new HashMap<String,List<EmployeeDetails>>();
public Data() {
}
#JsonAnyGetter
public Map<String, List<EmployeeDetails>> getEmployeeDetails() {
return employeeDetails;
}
}
I would use custom deserializer with few helper classes. To make the code (matter of opinion I guess) clearer, create the list object:
#SuppressWarnings("serial")
#Getter #Setter
public class EmployeeDetailsList extends ArrayList<EmployeeDetails> {
// this will hold the arbitrary name of list. like 5214
private String name;
}
Then this list seems to be inside an object, say Wrapper:
#Getter
#RequiredArgsConstructor
#JsonDeserialize(using = WrapperDeserializer.class)
public class Wrapper {
private final EmployeeDetailsList employeeDetailsList;
}
So there is annotation #JsonDeserializer that handles deserializing Wrapper. It is not possible to directly deserialize unknown field names to some defined type so we need to use mechanism like this custom deserializer that inspects what is inside Wrapper and determines what to deserialize and how.
And here is how the deserializer works:
public class WrapperDeserializer extends JsonDeserializer<Wrapper> {
private final ObjectMapper om = new ObjectMapper();
#Override
public Wrapper deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
TreeNode node = p.readValueAsTree();
// This is the place for caution. You should somehow know what is the correct node
// Here I happily assume there is just the one and first
String fName = node.fieldNames().next();
EmployeeDetailsList edl = om.readValue(node.get(fName).toString(),
EmployeeDetailsList.class);
edl.setName(fName);
return new Wrapper(edl);
}
}
Please check it carefully it is not perfect in sense finding alwasy the correct node and maybe the instantiation can be done in other ways better. But it shoudl give you a hunch how it could be done.
I'm starting using jackson json after Jaunt, but i can't understand some details in deserialization.
I have JSON response from server, here it is:
{
success: true,
stickers: [
{
id: "88899",
name: "",
img: ""
},
{
id: "13161",
name: "3DMAX",
img: ""
}
]
}
I have a Sticker class in my project
public class Sticker {
#JsonProperty("id")
private String id;
#JsonProperty("name")
private String name;
#JsonProperty("img")
private String imgUrl;
//getters and setters and constructors
}
I want to read this response and create a List of Stickers:
List(Sticker) stickerList;
**Another task (if it is possible with jackson tools), i want to create HashMap(String, Sticker) during deserilization instead of List(Sticker) **
How to do it easy and properly?
I have found a solution for List: I created class
public class StickerPage {
#JsonProperty("stickers")
private List<Sticker> stickerList;
public List<Sticker> getStickerList() {
return stickerList;
}
public void setStickerList(List<Sticker> stickerList) {
this.stickerList = stickerList;
}
}
And used it for this:
ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
StickerPage stickerPage = objectMapper.readValue(inputStream, StickerPage.class);
HashMap<String, Sticker> stickerHashMap = new HashMap<>();
for (Sticker sticker : stickerPage.getStickerList()) {
stickerHashMap.put(sticker.getName(), sticker);
}
But it looks weird i think, can you help me with this task?
I've tried so many ways, but without success to parse this Json to a Java Object using Gson library:
"return":{
"48388":{
"status":"canceled",
"operations":{
},
"created":"138232386",
"price":"12.50000",
"volume":"50.00000000",
"pair":"btc_brl",
"type":"buy"
},
"51714":{
"status":"canceled",
"operations":{
},
"created":"1365465421706",
"price":"1500.00000",
"volume":"0.10000000",
"pair":"btc_brl",
"type":"buy"
},
"48754":{
"status":"canceled",
"operations":{
},
"created":"1383237058",
"price":"600.00000",
"volume":"0.50000000",
"pair":"btc_brl",
"type":"buy"
}
"success":1
}
There is a lot of topics about this, but none of them cover this type of json mapping.
I'm convinced that there is a simple way to do that, any ideas? Thanks!
EDIT:
I'm trying this:
public class Test {
#SerializedName("return")
public Return1 _return;
}
public class Return {
public List<Map<String, Order>> order;
}
EDIT:
public class Order {
#SerializedName("id")
private int idOrder;
private String status;
private String created;
private String price;
private String volume;
private String pair;
private String type;
private List<Operations> operations;
// All the gets and sets here..
}
Gson doesn't initialize my order object. The order object is always null. I can't find the correct way to implement this mapping.
After a long battle I was able to solve using this solution:
public void deserialize() {
Gson gson = new Gson();
// For isr read InputStreamReader
Map<String, Object> map = gson.fromJson(isr, Map.class);
System.out.println(map.get("success"));
Map<String, Object> map2 = (Map<String, Object>) map.get("return");
// Show the contents of return
System.out.println(map2);
}
After that I used an Entry object to iterate and set the values of Order.
Thanks!