POJOs:
import lombok.Data;
#Data
public class CCMTRequest {
private MOEH cch;
private String filler1;
private CCMTCCD ccd;
private String uPwName;
}
#Data
public class MOEH {
private String c;
private int z;
private String dType;
}
#Data
public class CCMTCCD {
private dTime time;
private int x;
}
#Data
public class dTime {
private String dTime;
}
Test Class:
public class TestJacksonParser {
#Test
void load_jsonToPOJO() {
ObjectMapper mapper = new ObjectMapper();
ClassLoader load = this.getClass().getClassLoader();
File file = new File(load.getResource("request.json").getFile());
CCMTRequest req = null;
try {
req = mapper.readValue(file, CCMTRequest.class);
}
catch(Exception e) {
System.out.println(e.getMessage());
}
System.out.println("\nRequest: " + req);
}
}
request.json :
{
"cch" : {
"c" : "C",
"z" : 4678,
"dType" : "dtype"
},
"filler1" : "random filler1",
"ccd" : {
"time" : {
"dTime" : "4:35"
},
"x" : 34567
},
"uPwName" : "uPwName"
}
Error:
Unrecognized field "dType" (class com.spring.mapstruct.test.MOEH), not
marked as ignorable (3 known properties: "z", "c", "dtype"]) at
[Source: (File); line: 5, column: 14] (through reference chain:
com.spring.mapstruct.test.CCMTRequest["cch"]->com.spring.mapstruct.test.MOEH["dType"])
Request: null
Now, when I update my test class as :
public class TestJacksonParser {
#Test
void load_jsonToPOJO() {
ObjectMapper mapper = new ObjectMapper();
//ignore Unknown JSON Fields
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ClassLoader load = this.getClass().getClassLoader();
File file = new File(load.getResource("request.json").getFile());
CCMTRequest req = null;
try {
req = mapper.readValue(file, CCMTRequest.class);
}
catch(Exception e) {
System.out.println(e.getMessage());
}
System.out.println("\nRequest: " + req);
}
}
I get output as:
Request: CCMTRequest(cch=MOEH(c=C, z=4678, dType=null), filler1=random
filler1, ccd=CCMTCCD(time=dTime(dTime=4:35), x=34567), uPwName=null)
So how jackson is working here with lombok, is there an issue with properties "dType" and "uPwName" ?
first things first, next time please provide better example rather than random name properties. it's confusing.
your problem is because lombok generate getter and setter for property like "uPwName" becomes "getUPwName()" and "setUPwName()". jackson read it as "getuPwName" and "setuPwName";
the library both using different naming convention for getters and setters.
there are 2 approach to fix this:
for your quick fix:
ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
for better way to fix your problem: use better name for your properties.
Related
I'm trying to parse following JSON string with one field inside. Unfortunatelly still getting exception:
InvalidTypeIdException: Could not resolve type id 'pin' as a subtype of `com.example.dto.AuthorizationRequest`: known type ids = [AuthorizationRequest]
Here is base class:
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT ,use = JsonTypeInfo.Id.NAME)
#JsonSubTypes({
#JsonSubTypes.Type(value = AuthorizationRequest.class, name = "AuthorizationRequest")})
public interface IMessage {}
Derived class:
public class AuthorizationRequest implements IMessage {
#JsonProperty( value = "pin", required = true )
private String pin;
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
}
Test:
#Test
void test(){
String request =
"{\n"
+ " \"AuthorizationRequest\": {\n"
+ " \"pin\": \"1234\"\n"
+ " }\n"
+ "}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
AuthorizationRequest authorizationRequest = null;
try {
authorizationRequest = objectMapper.readValue(request, AuthorizationRequest.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
What am I missing? I need to use request name as json root element.
You can delete objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true) line. The error is due to the fact that the line unwraps the initial object so escalating of one level at the intern of the json file obtaining the {"pin" : "1234"} json with the ""AuthorizationRequest" label. The JsonTypeInfo.As.WRAPPER_OBJECT annotation indicates to the jackson library to escalate again of one level the json file so obtaining the "1234" string labelled by "pin".The JsonTypeInfo.Id.NAME compares the "pin" string with the names of subclasses and because of it fails causing the issue and the error message.
I am trying to reformat this json file to a different format. I never used jackson or gson before. I get the idea of it but I don't know how to implement it.
So what I have is a json file: file.json that contains:
{
"Fruits": [
{
"name": "avocado",
"organic": true
},
{
"name": "mango",
"organic": true
}
]
}
What I want is to get in this format:
{
"List Fruits":{
"Fruits": [
{
"name": "avocado",
"organic": true
},
{
"name": "mango",
"organic": true
}
]
}
}
Somehow add the "List Fruits" in the json file.
I am trying to use the jackson api but I don't know how.
Assign the JSON to String variable, for example assign the above JSON to variable called json:
String json = "..." // here put your JSON text;
Prepare classes for your objects:
class Fruit {
private String name;
private boolean organic;
}
class Fruits {
private List<Fruit> fruits;
}
then use Gson to convert JSON to your objects:
Gson gson = new Gson();
Fruits fruits = gson.fromJson(json, Fruits.class);
Next prepare wrapper class ListOfFruits for your fruits object:
class ListOfFruits {
private Fruits listOfFruits;
public ListOfFruits(Fruits fruits) {
listOfFruits = fruits;
}
}
Next pack your fruits object into another one:
ListOfFruits lof = new ListOfFruits(fruits);
And finally generate back the output JSON:
String newJson = gson.toJson(lof);
You do not need to create POJO model for reading and updating JSON. Using Jackson, you can read whole JSON payload to JsonNode, create a Map with required key and serialising to JSON back. See below example:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.util.Collections;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
JsonNode root = mapper.readTree(jsonFile);
Map<String, JsonNode> output = Collections.singletonMap("List Fruits", root);
System.out.println(mapper.writeValueAsString(output));
}
}
Above code prints:
{
"List Fruits" : {
"Fruits" : [ {
"name" : "avocado",
"organic" : true
}, {
"name" : "mango",
"organic" : true
} ]
}
}
I would highly recommend going through the documentations of Jackson or Gson libraries as you mentioned you are new.
I have created a sample git repo for this item. This sample uses Jackson API.
Visit https://github.com/rajramo61/jsonwrapper
final InputStream fileData = ClassLoader.getSystemResourceAsStream("file.json");
ObjectMapper mapper = new ObjectMapper();
InitialJson initialJson = mapper.readValue(fileData, InitialJson.class);
System.out.println(mapper.writeValueAsString(initialJson));
final FinalJson finalJson = new FinalJson();
finalJson.setListOfFruits(initialJson);
System.out.println(mapper.writeValueAsString(finalJson));
This is the Fruit class.
public class Fruit {
private String name;
private boolean organic;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean getOrganic() {
return organic;
}
public void setOrganic(boolean organic) {
this.organic = organic;
}
#Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
", organic=" + organic +
'}';
}
}
Here is FinalJson class detail. This is the class will wrap the initial json loaded from jsn file.
public class FinalJson {
private InitialJson listOfFruits;
#JsonProperty("List Fruits")
public InitialJson getListOfFruits() {
return listOfFruits;
}
public void setListOfFruits(InitialJson listOfFruits) {
this.listOfFruits = listOfFruits;
}
}
Here is InitialJson class detail. This is the class pulls data from json file.
public class InitialJson {
private List<Fruit> fruits;
#JsonProperty("Fruits")
public List<Fruit> getFruits() {
return fruits;
}
public void setFruits(List<Fruit> fruits) {
this.fruits = fruits;
}
#Override
public String toString() {
return "InitialJson{" +
"fruits=" + fruits +
'}';
}
}
You can fork the repo and close this in local and it should work fine.
My API needs to return a list of entry objects from the JSON below. I am using jersey and jackson. I would ideally like to only create a java class PermissionEnty , and my API to return a list of PermissionEntry objects from the JSON. I am not able to deserialize using the below approach? Can someone advise what could be the issue? I have added UNWRAP_ROOT_VALUE so I presume the 'list' node it ignored, and I would get items below 'list' node.
public class PermissionEntry {
private String id;
private String displayName;
private String memberType;
}
and the json;
{
"list": {
"pagination": {
"count": 5,
"hasMoreItems": false,
},
"entries": [
{
"entry": {
"displayName": "norma",
"id": "norma",
"memberType": "PERSON"
}
},
{
"entry": {
"displayName": "clara",
"id": "clara",
"memberType": "PERSON"
}
},
{
"entry": {
"displayName": "michael",
"id": "mich",
"memberType": "PERSON"
}
}
]
}
}
PermissionEntries
public class PermissionEntries {
#JsonProperty(value = "entries")
#JsonDeserialize(using = PermissionEntryDeserializer.class)
private List<PermissionEntry> entries;
public List<PermissionEntry> getEntries() {
return entries;
}
public void setEntries(List<PermissionEntry> entries) {
this.entries = entries;
}
}
Below is the deserializer that I am using
public class PermissionEntryDeserializer extends JsonDeserializer<List<PermissionEntry>> {
private static final String ENTRY = "entries";
private static final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
private static final CollectionType collectionType =
TypeFactory
.defaultInstance()
.constructCollectionType(List.class, PermissionEntry.class);
#Override
public List<PermissionEntry> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
ObjectNode objectNode = mapper.readTree(jsonParser);
JsonNode nodeEntries = objectNode.get(ENTRY);
if (null == nodeEntries // if no ENTRY node could be found
|| !nodeEntries.isArray() // or ENTRY node is not an array
|| !nodeEntries.elements().hasNext()) // or ENTRY node doesn't contain any entry
return null;
return mapper.readerFor(collectionType).readValue(nodeEntries);
}
}
Service API
public Optional<List<PermissionEntry>> getPermissionsForGroup(String groupName) {
Response response = getTarget()
.path("/api/group/" + groupName + "/members")
.request()
.get();
PermissionEntries list = response.readEntity(PermissionEntries.class);
}
I don't understand what you mean in this question 'Can someone please tell me how many java classes do I need to create to get a list of entries.' but you had already an entry object called PermissionEntry. You will have the list of this object.
This is the jersey client of your data with jakcson .
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);
String URL = "http://{{host}}:{{port}}/entry";
WebResource webResourceGet = client.resource(URL);
ClientResponse response = webResourceGet.accept("application/json").get(ClientResponse.class);
String output = response.getEntity(String.class);
ResponseList responseList= mapper.readValue(output , ResponseList .class);//here is the permissionEntry list that you wil have
Also, you should create an object given name as Pagination for pagination that is in the json data. You can make an another object that includes List<PermissionEntry> and Pagination called ResponseList.
I have a Json file :
[
{
"name":"Move",
"$$hashKey":"object:79",
"time":11.32818,
"endTime":18.615535
},
{
"name":"First Red Flash",
"$$hashKey":"object:77",
"time":15.749153
},
{
"name":"Pills",
"subEventTypes":[
"pull down bottle",
"unscrew lid",
"dump pills out",
"screw lid on",
"put bottle away"
],
"$$hashKey":"object:82",
"time":25.130175,
"subEventSplits":[
26.092057,
27.425881,
31.841594,
34.268093
],
"endTime":36.234827
}
]
I tried to parse this Json file using the Jackson.
I wrote the following code:
public class Holder{
public Holder(){};
//getter and setters
String name;
List<String> subEventTypes = new ArrayList<>();
Double time;
String $$hashKey;
Double endTime;
List<Double> subEventSplits = new ArrayList<>();
}
class MapperClass{
List<Holder> list = new ArrayList<>();
}
public static void main(String[] args) throws JsonProcessingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
List<Holder> list = mapper.readValue(new File("data.json"), mapper.getTypeFactory().constructCollectionType(
List.class, Holder.class));
}
When I run the program, it showed this error : "
No suitable constructor found for type [simple type, class parseJason$Holder]: can not instantiate from JSON object (need to add/enable type information?)
".
Is there anything wrong with my code? or I have to use another way to parse my Json file.
try
list = mapper.readValue(
jsonString,
objectMapper.getTypeFactory().constructCollectionType(
List.class, Holder.class));
I am trying to deserialize/map the below JSON to List<Bill> java object using Jackson json library. (this json was generated by jackson, Iam omitting that piece for brevity)
{"bills":[{"amount":"13","billId":"billid3"}]}
Here is my conversion method:
private static void convert(){
String jsonBill = "{\"bills\":[{\"amount\":\"13\",\"billId\":\"billid3\"}]}";
ObjectMapper mapper = new ObjectMapper();
List<Bill> bills = null;
try {
bills = mapper.readValue(jsonBill, new TypeReference<List<Bill>>() { });
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("bills = " + bills.size());
}
The Bill entity is below:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS)
public class Bill {
private String amount;
private String billId;
public String getBillId() {
return billId;
}
public void setBillId(String billId) {
this.billId = billId;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
}
and I get this error:
**org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.List out of START_OBJECT token
at [Source: java.io.StringReader#7a84e4; line: 1, column: 1]**
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:160)
at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:194)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:103)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:93)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1980)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1278)
Here is my simplified spring3 controller which returns the i/p json (with Jackson mapping configured as default view):
#ModelAttribute("bills")
#RequestMapping(value = "/", method = RequestMethod.GET)
public List<Bill> fetchBills() throws IOException {
Bill bill = new Bill();
bill.setAmount("13");
bill.setBillId("billid3");
List<Bill> bills = new ArrayList<Bill>();
bills.add(bill);
return bills;
}
I guess I am missing something obvious.. but not sure what it is.. Any ideas?
The problem lies not in your code, but your example input. What you're actually trying to deserialize is an object with a field named "bills", not a list! What you should be using as input is:
[{"billId":"billid3","amount":"13"}]
This is an array of objects, which is converted to a list.
Try using ObjectWriter instead of ObjectMapper
Writer writer=new StringWriter();
ObjectWriter oWriter=om.writerWithType(new TypeReference<List<Bill>>() {
});
oWriter.writeValue(writer, result);
I'm using jackson 1.9.2