How to de-serialize POJO contains HashTable? - gson

I have pojo like this:
public class Test implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String hash;
private java.util.Hashtable<Integer, Long> myTempTable;
public java.util.Hashtable<Integer, Long> getMyTempTable() {
return this.myTempTable;
}
public void setMyTempTable(java.util.Hashtable<Integer, Long> myTempTable) { this.myTempTable = myTempTable; }
//And some few variables
}
In response I get this POJO in JSON format but while converting this JSON to "Test" java object like this.
gson.fromJson(tempString, Test.class);
It is giving error as
java.lang.IllegalArgumentException: Can not set java.util.Hashtable field <package_name>.Temp.myTempTable to java.util.LinkedHashMap
Why GSON is converting HashTable to LinkedHashMap?
And does this error means?
UPDATE: JSON File as
{
"hash": "abc",
"myTempTable": {
"1": 30065833999,
"2": 34364325903,
"3": 536872959
}
}

For converting an Object to JSON String.
public static <T> String convertObjectToStringJson(T someObject, Type type) {
Gson mGson = new Gson();
String strJson = mGson.toJson(someObject, type);
return strJson;
}
For converting a JSON String to an Object.
public static <T> T getObjectFromJson(String json, Type type) {
Gson mGson = new Gson();
if (json != null) {
if (json.isEmpty()) {
return null;
}
}
return mGson.fromJson(json, type);
}
where
Type is type of your Object.
ex:
for object:
new TypeToken<YOUR_POJO>(){}.getType();
for list:
new TypeToken<List<YOUR_POJO>>(){}.getType();

Related

JSON decoding error: Cannot deserialize value of type `java.math.BigInteger` from Object value (token `JsonToken.START_OBJECT`); (Jackson)

It is necessary to deserialize the result from Mono<ResultSumDto> to JSON, then to sent to the client as JSON.
Controller
#GetMapping("v1/sequence/{startRange}/{endRange}")
Mono<ResultSumDto > getSumFromRange(
#PathVariable BigInteger startRange,
#PathVariable BigInteger endRange) {
ResultSumDto resultSumDto = ...
return Mono.just(resultSumDto);
}
#Configuration
public class JacksonObjectMapperConfiguration {
#Autowired
public void serializeBigInteger(ObjectMapper objectMapper) {
JsonFormat.Value formatValue =
JsonFormat.Value.forShape(JsonFormat.Shape.STRING);
objectMapper
.configOverride(BigInteger.class)
.setFormat(formatValue);
}
}
#Data
#Builder
public class ResultSumDto {
private final BigInteger sumSeq;
private final BigInteger [] seqRange;
private final Boolean isCached;
}
private Mono<ResultSumDto> buildResult(SeqDto dto) {
Mono<BigInteger> sumSeq =
calculateSumRangeValuesFibonacciSequence(dto);
BigInteger bigInteger = null;
try {
bigInteger = sumSeq
.toFuture()
.get();
} catch (InterruptedException | ExecutionException e) {
log.error(e.getLocalizedMessage());
Thread.currentThread().interrupt();
}
BigInteger[] rangeGiven = new BigInteger[]
{dto.getStartRange(), dto.getEndRange()};
return Mono.just(ResultSumSeqDto.builder()
.sumSequence(bigInteger)
.sequenceRange(rangeGiven)
.isCached(false)
.build()
);
}
But I have a mistake:
org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize value of type java.math.BigInteger from Object value (token JsonToken.START_OBJECT); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type java.math.BigInteger from Object value (token JsonToken.START_OBJECT)
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 1]
But after all, when I get values in endpoint, serialization to the BigInteger type goes without problems.
Who has any idea why it doesn't work and how it can be fixed. Share your knowledge on how to deserialize an array BigInteger and a field with the BigInteger type?
That's what worked in my case.
public class DeserializeResultCalculateSumSequence
extends StdDeserializer<ResultCalculateSumSequenceDto> {
public DeserializeResultCalculateSumSequence() {
this(null);
}
protected DeserializeResultCalculateSumSequence(Class<?> vc) {
super(vc);
}
#Override
public ResultCalculateSumSequenceDto deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext)
throws IOException, JacksonException {
JsonNode node = jsonParser
.getCodec()
.readTree(jsonParser);
BigInteger sumSequence = node
.get("sumSequence")
.bigIntegerValue();
ObjectMapper mapper = new ObjectMapper();
String sequenceRangeStr = node.get("sequenceRange").toString();
BigInteger[] sequenceRange = mapper
.readValue(sequenceRangeStr, BigInteger[].class);
boolean isCached = node
.get("isCached")
.asBoolean();
return ResultCalculateSumSequenceDto
.builder()
.sumSequence(sumSequence)
.sequenceRange(sequenceRange)
.isCached(isCached)
.build();
}
}
#Data
#Builder
#JsonDeserialize(using = DeserializeResultCalculateSumSequence.class)
public class ResultCalculateSumSequenceDto {
private final BigInteger sumSequence;
private final BigInteger [] sequenceRange;
private final Boolean isCached;
}

How to use Jackson for parse object follow json type?

I have two Json objects like :
Object 1
{
"value": {
"data": [
"John",
"Justin",
"Tom"
],
"isGraduated": false
}
}
Object 2
{
"value": {
"data": {
"info": {
"background": {
"primarySchool" : "A school",
"univeristy": "X univeristy"
},
"name": "John",
"gender": "male",
"dayOfBirth": "1995-04-24"
}
},
"isGraduated": false
}
}
How can I deserialize the data field to list of strings or class(I've already declared) by using Jackson?
Edit
Add class Info declaration.
public class Info {
#JsonProperty("background")
private BackGround backGround;
#JsonProperty("name")
private String name;
#JsonProperty("gender")
private String gender;
#JsonProperty("dayOfBirth")
private String dayOfBirth;
public static class BackGround {
#JsonProperty("primarySchool")
private String primarySchool;
#JsonProperty("univeristy")
private String univeristy;
}
}
Looking at your JSON objects, there is no way you can figure out what will be there in data parameter. So you can use JsonNode as type for data parameter.
Note: This is the object hierarchy I have created to represent JSON objects
#ToString
class Wrapper {
private Value value;
// getter & setter
}
#ToString
class Value {
private JsonNode data;
private Boolean isGraduated;
// getter & setter
}
#ToString
class Data {
private Info info;
// getter & setter
}
#ToString
class Info {
private Background background;
private String name;
private String gender;
private String dayOfBirth;
// getter & setter
#ToString
static class Background {
private String primarySchool;
private String univeristy;
// getter & setter
}
}
Then you can check the node type before deserialize between List<String> and Info.calss like this,
JsonNodeType type = value.getValue().getData().getNodeType();
You will see type = JsonNodeType.ARRAY if the json object is type 1 and type = JsonNodeType.OBJECT if the json object is type 2.
Check this exaple,
public class Main {
public static void main(String[] args) throws IOException {
// String s = "{\"value\":{\"data\":[\"John\",\"Justin\",\"Tom\"],\"isGraduated\":false}}";
String s = "{\"value\":{\"data\":{\"info\":{\"background\":{\"primarySchool\":\"A school\",\"univeristy\":\"X univeristy\"},\"name\":\"John\",\"gender\":\"male\",\"dayOfBirth\":\"1995-04-24\"}},\"isGraduated\":false}}";
ObjectMapper om = new ObjectMapper();
Wrapper wrapper = om.readValue(s, Wrapper.class);
JsonNodeType type = wrapper.getValue().getData().getNodeType();
if (type == JsonNodeType.ARRAY) {
List<String> data = om.convertValue(wrapper.getValue().getData(), new TypeReference<List<String>>() {});
System.out.println(data);
} else if (type == JsonNodeType.OBJECT) {
Data data = om.convertValue(wrapper.getValue().getData(), Data.class);
System.out.println(data);
}
}
}
Not the general approach but approach for your specific case
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = (ObjectNode) mapper.readTree(jsonContent);
JsonNode data = root.get("value").get("data");
if (data.has("info")) {
Info result = mapper.convertValue(data.get("info"), Info.class);
// handle result as Info instance
} else {
List<String> result = mapper.convertValue(data, new TypeReference<List<String>>() {});
// handle result as list of strings
}

Get the value of multiple map (Map inside of map) from postman

How can get the value of multiple key values (Map inside of map) from the postman
{
"message_key": {
"device_id": "12548652",
"message": "Y5482lsdfkOjEyNDUysdfsdfMTc1sdfOTM3MjU=",
"messageType": "Text"
}
}
Actually I want to bind value of message_key with domain to validate every properties.
I have found the answer e.g:
DTO:
public #Data class MessageKey {
#JsonProperty("device_id")
private String deviceId;
#JsonProperty("message")
private String message;
#JsonProperty("messageType")
private String messageType;
}
Controller:
public void test(#RequestBody Map<String, MessageKey> bodyParameters) {
MessageKey messageKey = bodyParameters.get("message_key");
System.out.println(messageKey);
}

Spring Data Mongodb: json string to BasicDBObject

I've created this custom converter:
#Component
#WritingConverter
public class MetadataWriterConverter implements Converter<Metadata, DBObject> {
#Override
public DBObject convert(Metadata metadata) {
DBObject dbObject = new BasicDBObject();
dbObject.put("name", metadata.getName());
dbObject.put("metadata", (BasicDBObject) BasicDBObject.parse(reference.getMetadata()));
dbObject.removeField("_class");
return dbObject;
}
}
I'm getting this exception:
Caused by: org.bson.BsonInvalidOperationException: readStartDocument can only be called when CurrentBSONType is DOCUMENT, not when CurrentBSONType is ARRAY.
The problem is on:
(BasicDBObject) BasicDBObject.parse(metadata.getMetadata())
the content of metadata.getMetadata is: "[{'departament': 'JUST'}]".
Metadata class is:
public class Metadata {
private String id;
private String user;
private String metadata;
}
The content of metadata field is a json string, I'm trying to convert to BasicDbObject, but the problem appears when this string is an json array: [{},{}].
Guess:
Metadata met = new Metadata();
met.setId("Mdt1");
met.setUser("user");
met.setMetadata("[{'departament': 'JUST'}]");
What I want to get is:
{
"id": Mdt1,
"user": "user",
"metadata": [{"departament": "JUST"}]
}
Any ideas about how to refactor my converter?
Actually, BasicDBObject.parse() expects a JSONObject instead of a JSONArray that you are passing in your example. Check the docs here - http://api.mongodb.com/java/current/com/mongodb/BasicDBObject.html#parse-java.lang.String-
Instead, you can try converting your reference.getMetadata() into a valid JSON String and then using BasicDBList for your JSONArray. Something like below:
#Component
#WritingConverter
public class MetadataWriterConverter implements Converter<Metadata, DBObject>
{
#Override
public DBObject convert(Metadata metadata) {
DBObject dbObject = new BasicDBObject();
dbObject.put("name", metadata.getName());
String jsonString = String.format("{\"data\": " + reference.getMetadata() + "}");
BasicDBObject basicDBObject = (BasicDBObject) BasicDBObject.parse(jsonString);
BasicDBList parsedList = (BasicDBList) basicDBObject.get("data");
dbObject.put("metadata", parsedList);
dbObject.removeField("_class");
return dbObject;
}
}

error in parsing JSON using GSON with retrofit API

this is POJO or model class that I am using, I'm able to get the response from server but it is throwing SyntaxException and MalformedJSONException
//Model class:
public class AppUser {
public Integer userID;
public String username;
public String password;
public String emailID;
public String accessToken;
}
//JSON Retrieved:
{
"userID": "123456",
"username": "rkumar",
"password": "rohitk",
"emailID": "rohitk#gmail.com",
"accessToken": "1weErtYo90ds8i9"
}
//JSON Deserializer
public class AppUserDeserializer implements JsonDeserializer<AppUser> {
#Override
public AppUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Log.d("Json element",json.toString());
return new Gson().fromJson(json, AppUser.class);
}
}
//Rest Client Constructor
public RestClient()
{
Gson gson = new GsonBuilder()
.registerTypeAdapter(AppUser.class, new AppUserDeserializer())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(baseURL)
.setConverter(new GsonConverter(gson))
.build();
signInService = restAdapter.create(SignInService.class);
}

Resources