How can I unmarhsaller json file like this?
{
"packageId": "11",
"jsScript": "var divideFn = function(a,b) { return a/b} ",
"functionName": "divideFn",
"tests": [
{
"testName": "test1",
"expectedResult": "2.0",
"params": [
2,
1
]
}
]
}
I have a class that works well with packageId, jsScrript, functionName, but not with the tests
public class Data {
private final int packageId;
private final String jsScript;
private final String functionName;
private final List<Tests> tests;
#JsonCreator
public Data(#JsonProperty("packageId") String packageId,
#JsonProperty("jsScript") String jsScript,
#JsonProperty("functionName") String functionName,
#JsonProperty("tests") List<Tests> tests) {
this.packageId = Integer.parseInt(packageId);
this.jsScript= jsScript;
this.functionName = functionName;
this.tests = tests;
}
}
public class Tests{
public final String testName;
public final int expectedResult;
#JsonCreator
public Tests(#JsonProperty("testName") String testName,
#JsonProperty("expectedResult") String expectedResult){
this.testName= testName;
this.expectedResult = Integer.parseInt(expectedResult);
}
}
What should I change in classes to make it work well?
I also tried to read tests like String, but it didn't help
It seems that you have encountered some problems for deserializing the JSON array tests to objects. There are several methods to solve this.
Method 1
Add #JsonIgnoreProperties(ignoreUnknown = true) on your class Tests to prevent your code from the exception of Unrecognized field "params".
Method 2
Deserialize JSON array tests to List<JsonNode> if it is not important and you won't further parse it in the future.
Method 3
Use follwing class for mapping JSON array tests to List<Test>.
class Test {
private String testName;
private Float expectedResult;
private List<Integer> params;
//general getters ans setters
}
BTW, I don't think you need to use #JsonCreator for deserialization.
Related
public class Baseproperties
{
#JsonProperty("id")
private String id ;
private Integer ccode;
//...set and geters
}
public class Person
{
#JsonProperty("name")
private String name ;
private Integer age;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public class Cars
{
#JsonProperty("model")
private String Model ;
private Integer yearOfMake;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public MessageWrapper
{
#JsonProperty("ct")
private String classType;
private Object data;
//...set and geters
}
I need to serialise MessageWrapper class to json, but the approach fails due to unable to desearialize the Object data;
here i am reading the classType and desearializing it to either Person or CarType
//Person
{
"name": "arnold",
"age": 21
}
//car
{
"model": "Moriz",
"yearOfMake": 1892
}
//example MessageWrapper
String s= "{
"ct": "<packagename>.car",
"data": {
"model": "Moriz",
"yearOfMake": 1892
"props":{
"id" : "12312",
"ccode" :33
}
}
}"
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
MessageWrapper mw = mapper.readValue(s, MessageWrapper.class);
if(mw.getclassType().toString().equals("<packagename>.car"))
Cars cw = mapper.readValue(mw.getData(), Cars.class);
but cw is wrong // serialise fails.
This is because there is no ObjectMapper::readValue method that takes Object as first argument.
By default with your approach Jackson will deserialize your data field to LinkedHashMap because you have given it Object type.
To then deserialize this value manually you will have to use ObjectMapper::convertValue and passing Cars.class as argument :
Cars cw = mapper.convertValue(mw.getData(), Cars.class);
And also get rid of :
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
as it does not seem to be needed here.
And just to add, I am not sure that approach with such dynamic data is good because, if you will be creating more and more types of objects you will end up with a tower of ifs or colosal switch statement.
I had a Java Class linked to a MongoDB Collection:
#Document(collection = "my_collection")
public class Ev extends MyDTO{
#Id
private String id;
#Indexed
private String sessionId;
private List<String> findings;
}
I had to change findings in this
private List<MyObject> findings;
Declared as
public class MyObject {
private String find;
private String description;
private int number;
private List<SecondaryObj> details;
}
Here are the constructors
public MyObject(String find, int number) {
super();
this.find= find;
this.number= number;
}
public MyObject(String find, int number, List<SecondaryObj> details) {
super();
this.find= find;
this.details = details;
this.number= number;
}
So in mongoDB I have a situation similar to
{
"_id" : ObjectId("5b487a2667a1aa18f*******"),
"sessionId" : "abc123mySessionId",
"findings" : [
{
"find" : "HTTPS",
"description" : "I found HTTPS",
"number" : 10,
"details": [
{"a":"1", "b":"2"},
{"a":"2", "b":"3"}
]
},
{
"find" : "NAME",
"description" : "I found name",
"number" : 3,
"details": [
{"a":"1", "b":"2"},
{"a":"2", "b":"3"}
]
}
]
}
I obviously updated all the methods to match the new data set, but if I try to retrieve
Query searchQuery = new Query(Criteria.where("sessionId").is("abc123mySessionId"));
Ev result = mongoTemplate.findOne(searchQuery, Ev.class);
I obtain this error
Request processing failed; nested exception is org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.my.project.domain.MyObject using constructor NO_CONSTRUCTOR with arguments
with root cause
java.lang.NoSuchMethodException: om.my.project.domain.MyObject.<init>()
I'm using spring-data-mongodb version 2.0.8 and mongo-java-driver version 3.8.0
I think I should declare MyObject somewhere, but I'm pretty new in Spring, so I'm trying in a kinda blind way... Any suggestion?
You have two non-zero-argument constructors and Spring does not know which one to call. It tries to call no-args constructor, but your class does not have that one.
Check Spring Data Mongo docs
You can create no-args constructor and mark it with #PersistenceConstructor annotation. This way Spring calls it to create an object and sets fields via reflection based on a document fields names, so no setters are required.
#Document(collection = "my_collection")
public class Ev extends MyDTO{
#Id
private String id;
#Indexed
private String sessionId;
private List<MyObject> findings;}
public class MyObject {
private String find;
private String description;
private int number;}
In this it work fine for me in spring-boot-starter-data-mongodb - version 2.0.3.RELEASE
My android application use flexjson library to deserialize json data string received from server via RESTfull webservice. But when deserialize i get error.
flexjson.JSONException: [ data.status ]: Don't know how to bind Clock_in into class wfa.com.tma.wfa.type.TimeClockStatus. You might need to use an ObjectFactory instead of a plain class.
this is my String
{
"data":
{
"todayShift":
{
"startTime":"1970-01-01T13:30:00Z",
"endTime":"1970-01-02T00:00:00Z",
"office":
{
"id":1,"name":"Location Test 1"
}
},
"currentTime":"2017-10-12T07:47:11Z",
"status":"Clock_in",
"latestTime":"2017-10-12T07:46:13Z",
"latestOffice":{"id":1,"name":"Location Test 1"}},
"meta":{"type":"TimeClockDto"}
}
the DTO of this String
public class TimeClockDto implements Serializable
{
private static final long serialVersionUID = 1L;
private TodayShiftDto todayShift;
private String currentTime;
private TimeClockStatus status;
private String latestTime;
private BaseLocationDto latestOffice;
public TimeClockDto(TodayShiftDto todayShift, String currentTime,
TimeClockStatus status, String latestClockInTime,
BaseLocationDto latestOffice)
{
this.todayShift = todayShift;
this.currentTime = currentTime;
this.status = status;
this.latestTime = latestClockInTime;
this.latestOffice = latestOffice;
}
//getter, setter
}
`and the deserialize code
and the enum class
public enum TimeClockStatus
{
Clock_in, Clock_out;
}
I have solve this problem by using EnumObjectFactory
TimeClockDto result = new JSONDeserializer<TimeClockDto>
.use("data", TimeClockDto.class)
.use("data.todayShift", TodayShiftDto.class)
.use("data.status", new EnumObjectFactory())
.use("data.latestOffice", BaseLocationDto.class)
.deserialize(param.getResult(),TimeClockDto.class);
I need transform json in another diferent json , im using #JsonProperty annotation for change name fields JSON result , but i dont know access fields encapsulate in differents json level for example :
{ "prop1" : "value1",
"prop2" : "value2",
"prop3" : {
"prop4" : "value4",
"prop5" : {
"prop6" : "value6"
}
}
}
json result
{
"prop1_new_name":"value1",
"prop4_new_name":"value4",
"prop6_new_name":"value6"
}
This seems like a continuation of your previous question. So, in addition of using #JsonUnwrapped as explained in the answer, you need to add #JsonProperty on the field in the class where it is declared. Modifying the previous answer with #JsonProperty gives you this:
#RunWith(JUnit4.class)
public class Sample {
#Test
public void testName() throws Exception {
SampleClass sample = new SampleClass("value1", "value2", new SubClass("value4", "value5", new SubSubClass("value7")));
new ObjectMapper().writeValue(System.out, sample);
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SampleClass {
private String prop1;
private String prop2;
#JsonUnwrapped
private SubClass prop3;
public SampleClass(String prop1, String prop2, SubClass prop3) {
this.prop1 = prop1;
this.prop2 = prop2;
this.prop3 = prop3;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubClass {
#JsonProperty("prop4_new_name")
private String prop4;
private String prop5;
#JsonUnwrapped
private SubSubClass prop6;
public SubClass(String prop4, String prop5, SubSubClass prop6) {
this.prop4 = prop4;
this.prop5 = prop5;
this.prop6 = prop6;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubSubClass{
#JsonProperty("prop7_new_name")
private String prop7;
public SubSubClass(String prop7) {
this.prop7 = prop7;
}
}
}
With this as a result:
{"prop2":"value2","prop5":"value5","prop7_new_name":"value7","prop4_new_name":"value4","prop1_new_name":"value1"}
"prop3" would be a Map in your Java object when deserializing (if you have it properly annotated). Then you can create a custom JsonSerializer to output your expected result.
To create your custom JsonSerializer, you can follow this guide: http://dev.sghill.net/2012/04/how-do-i-write-jackson-json-serializer.html
I am trying to parse through a JSON string and convert it to the following POJO:
package apicall;
//POJO representation of OAuthAccessToken
public class OAuthAccessToken {
private String tokenType;
private String tokenValue;
public OAuthAccessToken(String tokenType,String tokenValue) {
this.tokenType=tokenType;
this.tokenValue=tokenValue;
}
public String toString() {
return "tokenType="+tokenType+"\ntokenValue="+tokenValue;
}
public String getTokenValue() {
return tokenValue;
}
public String getTokenType() {
return tokenType;
}
}
In order to do this I have written the following code:
Gson gson=new Gson();
String responseJSONString="{\"access_token\" : \"2YotnFZFEjr1zCsicMWpAA\",\"token_type\" : \"bearer\"}";
OAuthAccessToken token=gson.fromJson(responseJSONString, OAuthAccessToken.class);
System.out.println(token);
When I run the code, I get the following output:
tokenType=null
tokenValue=null
Instead of
tokenType=bearer
tokenValue=2YotnFZFEjr1zCsicMWpAA
I don't understand if there's anything I've done wrong. Please help.
You can get the expected result by annotating your fields like:
#SerializedName("token_type")
private final String tokenType;
#SerializedName("access_token")
private final String tokenValue;
How is Gson supposed to know how to populate your object? You don't have a no-arg constructor, and the fields of your object don't match the fields in the JSON object.
Make your object as following:
public class OAuthAccessToken {
private String accessToken;
private String tokenType;
OAuthAccessToken() {
}
...
}
The class should have the exact field name as the json, so if your json have 2 keys: "access_token" and "token_type", the class should have 2 fields:
private String access_token;
private String token_type;
And, of course you need to change the getters/setters accordingly.