cannot serialize interface object to json using jakson - java

Im trying to convert a java object to a json according to an API's declared pattern, using jakson.
but I couldnt figure it out.
how should I do that?
Here are my classes
ProcessValueBaseDto
package com.ir.tsn;
public class ProcessValueBaseDto implements Serializable {
private String id;
private ProcessValue value;
}
//methods Ommited
ProcessValue
package com.ir.tsn;
public interface ProcessValue<T> extends Serializable {
void setValues(T values);
}
//methods Ommited
ProcessValueDto
package com.ir.tsn;
public class ProcessValueDto implements
ProcessValue<List<String>> {
private List<String> values;
}
//methods Ommited
the excpected json should be like this
{
"id": "id1",
"value": {
"com.alz.ProcessValueDto": {
"values": [
"500000000"
]
}
}
}
com.alz.ProcessValueDto is the name of one of the ProcessValue.class implementations in API
thank you in advance

I can't really understand the question, but the one problem I see from the code you posted is that you have two classes with the same name. Also if the code is all in the same file you should split it up as you can't have more than one public class or interface in the same file.

You can use the given below class for given JSON.
public class MyValue
{
public List<string> values { get; set; }
}
public class Value
{
public MyValue MyValue { get; set; }
}
public class RootObject
{
public string id { get; set; }
public Value value { get; set; }
}

Related

Id json deserialization with Jackson MixIn (for null values)

I've a problem with deserialization of Id class. I have class:
public class Id{
private String raw;
public Id(String raw) {
this.raw = raw;
}
public abstract String getRaw() {
return raw;
}
}
and MixIn:
abstract class IdMixIn {
#JsonCreator
public IdMixIn(String raw) {
}
#JsonValue
public abstract String getRaw();
}
and json array:
[
"test-id",
"null",
null
]
First two Id-s after deserialization are correct - they are (Id(raw=null)) but the third one is simply null. Can I somehow achieve same effect for "null" and null?
Thanks for help!

Spring-boot hateoas convert hateoas links to object instead of collection

I am using spring-boot along with Hateoas. One of my API exposes hateoas links as a collection "_links":[ instead if an object "_links":{. I am not sure why it is using array notation instead of an object. Please find the code below. Any help would be appreciated.
public class Book {
private String id;
private BookInfo bookInfo;
}
public class BookInfo extends ResourceSupport{
private String bookUid;
private String bookName;
private String authhorName;
private String bookGenre;
#Override
#JsonProperty("_links")
#JsonInclude(JsonInclude.Include.NON_NULL)
public List<Link> getLinks() {
return super.getLinks();
}
}
#RestController
#RequestMapping(value = "/api/v1/", produces = APP_JSON)
public class BookController {
#GetMapping("getBooks")
public ResponseEntity<Book> getTransactionStatus() {
Book book = bookRepo.getAllBooks();
book.getBookInfo().add(addLinks(book.getId()));
return ResponseEntity.ok().contentType(MediaType.valueOf(APP_JSON)).body(book);
}
public SuperLink getBookInfoLinks(String bookUid) {
return new SuperLink(
linkTo(methodOn(BookController.class).getBook(bookUid))
.withRel("retrieve-book").expand(),APP_JSON);
}
}
public class SuperLink extends Link {
#XmlAttribute
#JsonInclude(JsonInclude.Include.NON_NULL)
private String accepts;
public SuperLink(Link link) {
super(link.getHref(), link.getRel());
}
public SuperLink(Link link, String accepts) {
super(link.getHref(), link.getRel());
this.accepts = accepts;
}
public String getAccepts() {
return accepts;
}
public void setAccepts(String accepts) {
this.accepts = accepts;
}
}
Actual output
{
"id":"bookId",
"BookInfo":{
"bookUid":"bookUid",
"_links":[
{
"rel":"retrieve-book",
"href":"http://localhost/api/v1/book/bookId",
"accepts":"application/json"
}
]
}
}
Expected output
{
"id":"bookId",
"BookInfo":{
"bookUid":"bookUid",
"_links":
{
"retrieve-book": {
"href":"http://localhost/api/v1/book/bookId",
"accepts":"application/json"
}
}
}
}
This is happening because you are using List in you code.
#Override
#JsonProperty("_links")
#JsonInclude(JsonInclude.Include.NON_NULL)
public List<Link> getLinks() {
return super.getLinks();
}
You should use Link object instead of List of Link.
The links should be serialized as a map, not as a list. You either convert it into a map yourself or you can use custom serializer/deseralizer for that. Fortunately Spring already has them:
#Override
#JsonProperty("_links")
#JsonInclude(Include.NON_EMPTY)
#JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
#JsonDeserialize(using = Jackson2HalModule.HalLinkListDeserializer.class)
public List<Link> getLinks() {
return super.getLinks();
}
--- edit
In order to make it work you will need the halJacksonHttpMessageConverter bean in the list of message-converters. Create a WebMvcConfigurer and add the halJacksonHttpMessageConverter to the converters in the extendMessageConverters method.
#Autowired
private HttpMessageConverter halJacksonHttpMessageConverter;
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(halJacksonHttpMessageConverter);
}
You should add it to the front of the list, or remove the original jacksonHttpMessageConverter from the list.

How do I create Json Array in Java8 and only print json if I set value for it?

I am trying to generate the following using fasterxml jackson.. but I am stuck. I can't seem to work out how to create arrays.
{
"setAccId":"12345",
"groupOf":null,
"isEnabled":false,
"list":[
{
"student":"jim",
"type":"S_A",
"retro":null
},
{
"student":"bob",
"type":"S_A",
"retro":null
}
],
"sort":[]
}
I have two classes. One has the Json properties, and the other is where I print it.
Below class (DynamicJsonHelper) is where I have all the json properties
package com.company.jsonfc;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonPropertyOrder({
"accId",
"groupOf",
"isEnabled"
})
public class DynamicJsonHelper {
public String accId;
public String groupOf;
public List studentList;
#JsonProperty("accId")
public void setAccId(String accId) {
this.accId = accId;
}
#JsonProperty("groupOf")
public void setGroupOf(String groupOf) {
this.groupOf = groupOf;
}
#JsonProperty("isEnabled")
public boolean isEnabled() {
return false;
}
#JsonProperty("studentList")
public List<StudentList> studentList() {
return studentList;
}
}
Student List Class (as suggested)
class StudentList {
String student;
String type;
String retro;
}
And here is class (PrintJson) where I call it.
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.company.jsonfc.DynamicJsonHelper;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class PrintJson {
#Test
public void create_json() throws JsonProcessingException {
final JsonNodeFactory factory = JsonNodeFactory.instance;
DynamicJsonHelper dynamicJsonHelper = new DynamicJsonHelper();
String jsonString;
ObjectMapper mapper = new ObjectMapper();
dynamicJsonHelper.setAccId("12345");
jsonString = mapper.writeValueAsString(dynamicJsonHelper);
System.out.println(jsonString);
}
}
This results in printing the following:
{
"setAccId":"12345",
"groupOf":null,
"isEnabled":false
"studentList":null
}
1) How do I add the list:[ ... ] array & the sort: [ ] at the end too?
2) In class PrintJson, I don't set value for groupOf but it is still created in Json. How do I set it so if I set value, it is printed.. otherwise it is not included in the json being printed.
I would appreciate if you took my code and gave me example based on it for better understanding please
1) How do I add the list:[ ... ] array & the sort: [ ] at the end too?
Answer: You can create two more classes one for list and one for sort. Now in the class DynamicJsonHelper you can add both of them like you have added accId or isEnabled
and they will be printed. Make sure to add the fields you want in them as instance variables in both of the classes. For example for list you can have a class like:
class StudentList{
String student;
String type;
String retro;
}
Now add a field in your class DynamicJsonHelper as List<StudentList>. Similarly you can do for sort.
2) In class PrintJson, I don't set value for groupOf but it is still
created in Json. How do I set it so if I set value, it is printed..
otherwise it is not included in the json being printed.
Answer: You can either use Object mapper and set it to ignore the null fields during serialization. For eg: mapper.setSerializationInclusion(Include.NON_NULL);
Or you can set it at class level to ignore null values if any. For eg:
#JsonInclude(Include.NON_NULL)
class Test
{
String t;
}
As mentioned in the comments by aBnormaLz above doesn't work if the type is primitive like you have for isEnabled. So consider changing it to Boolean and ensure the same for other fields also.
Edit:
#JsonPropertyOrder({
"accId",
"groupOf",
"isEnabled"
})
#JsonInclude(JsonInclude.Include.NON_NULL)
public class DynamicJsonHelper {
public String accId;
public String groupOf;
public List<Student> studentList;
#JsonProperty("accId")
public void setAccId(String accId) {
this.accId = accId;
}
#JsonProperty("groupOf")
public void setGroupOf(String groupOf) {
this.groupOf = groupOf;
}
#JsonProperty("isEnabled")
public boolean isEnabled() {
return false;
}
#JsonProperty("studentList")
public void setStudentList(List<Student> list) {
this.studentList = list;
}
}
class Student {
private String student;
private String type;
private String retro;
public Student(String student, String type, String retro) {
this.student = student;
this.type = type;
this.retro = retro;
}
public String getStudent() {
return student;
}
public void setStudent(String student) {
this.student = student;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getRetro() {
return retro;
}
public void setRetro(String retro) {
this.retro = retro;
}
}
class HelperTest{
public static void main(String[] args) throws JsonProcessingException {
DynamicJsonHelper dynamicJsonHelper = new DynamicJsonHelper();
String jsonString;
ObjectMapper mapper = new ObjectMapper();
dynamicJsonHelper.setAccId("12345");
List<Student> list = Arrays.asList(new Student("s1", "t1", "r1"), new Student("s2", "t2", "r2"));
dynamicJsonHelper.setStudentList(list);
jsonString = mapper.writeValueAsString(dynamicJsonHelper);
System.out.println(jsonString);
}
}
After executing the program the output is as shown below:
{
"accId": "12345",
"isEnabled": false,
"studentList": [
{
"student": "s1",
"type": "t1",
"retro": "r1"
},
{
"student": "s2",
"type": "t2",
"retro": "r2"
}
]
}
You missed a point that you have to have third class and it must have property of type java.util.List or array and name list for your example.
e.g.
public class JsonHolder {
// appropriate Json/Jackson annotations ommitted
private String setAccId;
private String groupOf;
private boolean isEnabled;
private List<DynamicJsonHelper> list;
private String[] sort;
// .. getter/setters ...
}
then you have to create that object and when you created your DynamicJsonHelper put it into list or array.
After all you can serialize JsonHolder object and you will see your java List or Array as JSON array.
UPD: just note that in JSON structure like { ... } is an object and in Java there must be a class for it.
So, starting with JSON structure you posted
{
"setAccId":"12345",
"groupOf":null,
"isEnabled":false,
"list":[
{
"student":"jim",
"type":"S_A",
"retro":null
},
{
"student":"bob",
"type":"S_A",
"retro":null
}
],
"sort":[]
}
it is an object (let name it JsonHolder) with properties named setAcctId, groupOf, isEnabled, list, sort
So you have to have a Java class for it (similar as you did for your DynamicJsonHelper. You can use any #Json annotations you'd like to the same way (I omitted them and left for you). Even you will not have them Jackson or any other JSON serialiser will use property names in Java class by as default.
I mean as example your #JsonProperty("accId")
#JsonProperty("accId")
public void setAccId(String accId)
is not required as long as getter/setter/property named also getAcctId, setAcctId, acctId. Jackson will use that if there is no #JsonProperty annotation.
BTW it is better to do it as you did for code readability. :-)
Per your question:
list and sort properties in JSON are arrays. Jackson parses Java collections classes like List, Set or Arrays to JSON arrays.
Then according to required JSON structure list property is a such collection of DynamicJsonHelper objects you created. in Java class, List or Array is just your choice - use what is more suitable for you. I recommend to use a List rather than Array. Work with arrays in Java is not a good idea. :-)
So far you just created a Java class DynamicJsonHelper only for objects which must be in list property of JsonHolder object. What's left is to create that "JsonHolder" class and give that object to Jackson to serialize it into required JSON structure.
There are bunch of #Json annotations you can use to allow or not null or empty values, change property names, exclude Java class properties to be serialized and so, and so... All is up to you... good luck!

Gson.fromJson() always returns null

I'm trying to deserialize some JSON to a generic class. The structure is roughly as follows:
public abstract class AbstractRequest implements Constants
{
public abstract Class<?> getClazz();
}
public class GetTransaction extends AbstractTransactionRequest
{
#Override
public Class<Transaction> getClazz()
{
return Transaction.class;
}
}
And the Transaction class is as follows:
public class Transaction implements Serializable
{
#SerializedName("_id")
private String id;
private int amount;
#SerializedName("details")
private Map<String, String> transactionDetails;
private class Details {
private String issuer;
#SerializedName("redirect_url")
private String redirectUrl;
#SerializedName("approval_url")
private String approvalUrl;
}
}
All classes are slightly more complicated but I removed irrelevant variables.
Here's a JSON sample:
{
"_id": "2740096e-58a0-4677-8947-84fcc54cfaad",
"amount": 456,
"details": {
"issuer": "MYBANK",
"redirect_url": "https://example.com/redirect/MYBANK",
"approval_url": "https://example.com/v1/transaction/2740096e-58a0-4677-8947-84fcc54cfaad/MYBANK/authorize"
}
}
Now, I deserialize this code by doing
response.setData(Gson.fromJson(this.getResponse(), this.request.getClazz()));
Where setData accepts a Object, and getResponse returns the JSON as a String. I then do (Transaction) response.getData() which casts data to a Transaction. However, this is always null. Can anyone tell my why?
Sorry for the potentially confusing code!

GSON with several known classes

I have the following json
{ "file": {"file": "foo.c", "owner": "user123"}
"methods": [{"name": "proc1", "value":"val"}, {"name":"proc2","value":"val2"}]
etc...
}
I know that I can do something like
class file{
public String file
public String owner
}
class methods{
public String name
public String value
}
and I can either call
File file= gson.fromJson(jsonInString, File.class);
methods[] array = gson.fromJson(jsonInString, methods[].class);
but what do I do if I need to handle a complex json that contains many objects all togther
I cannot specify gson.fromJson(jsonInString, ListOfClasses)
I normally follow this approach to get any complex classes converted from json to object. This approach works for almost everything like list, map etc. The idea is simple create holders for the complex classes and then create the classes. Give as much depth as much required. The trick is to match name in Json and your holders (and subclasses).
File Config:
class FileConfig{
public String file;
public String owner;
//define toString, getters and setters
}
Method Class:
class Method{
public String name;
public String value;
//define toString, getters and setters
}
Method Config:
class MethodConfig{
List<Method> methods = null;
//define toString, getters and setters
}
Holding the Config:
public class HolderConfig {
private FileConfig file = null;
private MethodConfig methods = null;
public FileConfig getFile() {
return file;
}
public void setFile(FileConfig file) {
this.file = file;
}
public MethodConfig getMethods() {
return file;
}
public void setMethods(MethodConfig methods) {
this.methods = methods;
}
}
Building the config:
public class HolderConfigBuilder {
public static HolderConfig build(JsonObject holderConfigJson) {
HolderConfig configHolderInstance = null;
Gson gsonInstance = null;
gsonInstance = new GsonBuilder().create();
configHolderInstance = gsonInstance.fromJson(holderConfigJson,HolderConfig.class);
return configHolderInstance;
}
}
Demo class:
public class App
{
public static void main( String[] args )
{
HolderConfig configHolderInstance = null;
FileConfig file = null;
configHolderInstance = HolderConfigBuilder.build(<Input Json>);
file = configHolderInstance.getFile();
System.out.println("The fileConfig is : "+file.toString());
}
}
Input Json:
{ "file": {"file": "foo.c", "owner": "user123"}
"methods": [
{"name": "proc1", "value":"val"},
{"name":"proc2","value":"val2"}
]
}
Note: Write the code to get Input JSON in your test code.
In this way whenever you add more elements to your JSON you have to create a separate class for that element and just add the element name same as in your json into the HolderConfig. You need not change rest of the code.
Hope it helps.

Categories

Resources