Serialize a class to json in diffrent ways - java

Is there any way to serialize a class into json but only with fields I want to use in particular case without need of creating multiple variations of class?
Let's take an example:
class User{
#JsonField
private String name;
#JsonField
private String surname;
#JsonField
private String hashedCode;
#JsonField
private String city;
#JsonField
private String anotherDummyString;
}
Now in one of my methods I would like to have a mapping to json Object which only contains name, city and anotherDummyString.
In Second method I want to have surname and city. In third method ... .
Is there any pleasant and neat way to achive this?
I was wondering if I can "hide" these fields which I don't need.

Are you looking for something like this? (Using javax.json)
JsonObject getJson1() {
return Json.createObjectBuilder().add("name", this.name).add("city", this.city).build();
}
JsonObject getJson2() {
return Json.createObjectBuilder().add("surname", this.surname).add("city", this.city).build();
}
Just .add what you need in each function call.

I hope you are looking for a kind of filter for your fields in Class
This can be achieved using Jackson #JsonFilter
package com.concretepage;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonFilter("student")
public class Student
{
#JsonProperty("name")
private String name;
#JsonProperty("surname")
private String surname;
#JsonProperty("hashedCode")
private String hashedCode;
#JsonProperty("city")
private String city;
#JsonProperty("anotherDummyString")
private String anotherDummyString;
}
Create a simple filter for you above class
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("student",
SimpleBeanPropertyFilter.serializeAllExcept("name", "city","anotherDummyString"));
Set it to a object mapper
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);
To get the json message
//Pass the student object
String jsonData = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(student);
You must able to have you 2 variance of class by creating one more sample filter like above

Related

How to create query param body with multiple key param values

In the below hashmap you can see, I have list of key param values for which I need to automate cases for multiple values without repeating the hashmap rather it would be and update.
How I am doing it:
1st test case
HashMap<String, String> queryParam = new HashMap<>();
queryParam.put("Name", Name);
queryParam.put("street","street" );
queryParam.put("city","city" );
queryParam.put("state", "state");
queryParam.put("postalCode","postalCode" );
queryParam.put("country", "country");
queryParam.put("email", "email");
queryParam.put("website","website" );
queryParam.put("phone", "phone");
Response response = request.auth().basic(uname, pwd).body(queryParam).contentType(APPLICATION_JSON)
.post().then().extract()
.response();
Now if you see the above hashmap, it has mandatory params, some optional and then each param has different validation. Now it terms to cover all the testcases with each keys, above haspmap is repeating and values or keys are changing. I would like to do this in better and efficient way of it.
Instead of using Map<K, V>, you should use Java POJO. Using constructor to setup default value, then using setter to change value. It's more efficient.
One more thing, you could apply Factory design pattern to build object with desired value for each test case.
Test example
#Test
void test1() {
QueryObject query = QueryObjectFactory.getDefaultValue();
Response res = given().contentType(ContentType.JSON)
.body(query)
.post("to_your_api_endpoint");
}
Factory class
public class QueryObjectFactory {
public static QueryObject getDefaultValue() {
QueryObject queryObject = new QueryObject();
queryObject.setName("name");
queryObject.setStreet("street");
queryObject.setCity("city");
queryObject.setCountry("country");
queryObject.setState("state");
queryObject.setPostalCode("postalCode");
queryObject.setEmail("email");
queryObject.setWebsite("website");
queryObject.setPhone("phone");
return queryObject;
}
}
POJO
note: I use lombok to generate getter and getter --> reduce complex of POJO class.
import lombok.Data;
#Data
public class QueryObject {
private String name;
private String street;
private String city;
private String state;
private String postalCode;
private String country;
private String email;
private String website;
private String phone;
}

How to declare a variable or Object of any class type in Java

I am quite new to Java and I am trying to deserialize the JSON using Jackson and I facing some minor issue with regards to declaring the Object/Variable type. I will provide all the codes then explain the issue for easy understanding.
I have an enum that will have the required type values:
public enum IdentifierTypeValues {
Type1,
Type2,
Type3,
//Constructor and Getter of enum values
}
Then for each of these type, I have different classes which will have different input and do a completely different type of process:
public class GenerateType1 {
private String name;
private String age;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType2 {
private String address;
private String city;
private String country;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType3 {
private String firstName;
private String lastName;
private String fullName;
//Getter and Setter
//Some required process based on these values
}
Now I have a wrapper class for these type of classes which will take the type based on enum and typeInfo values. I want the typeInfo values to be any of the class based type something like this:
public class TypeSyntax {
private IdentifierTypeValues indeitiferType;
private GenerateType1 / GenerateType2 / GenerateType3 identifierTypeValues;
//Here the identifierTypeValues can have the values for anytype
//How to declare a variable of any of these class type?
}
This is the class that will be used by my JSON for deserializing. I know I can add a wrapper class of those 3 types and provide that wrapper class as a type class for this. Something like this:
public class WrapperClass{
private GenerateType1 type1;
private GenerateType2 type2;
private GenerateType3 type3;
}
public class TypeSyntax{
private IdentifierTypeValues indeitiferType;
private WrapperClass identifierTypeValues;
//But using this approach will change my JSON structure which I do not want to do.
}
My JSON structure is something like this and I would like to keep it in the same way.
{
"indeitiferType":"Type1",
"identifierTypeValues":{
"name":"Batman",
"age":"2008"
}
}
Is there a way I can declare the variable of multiple type class? or any better approach to handle this by keeping the json format same? I tried searching but I am unable to search what exactly so any help would be really appriciated.
Because the type identifier exists on a different level than the other properties a wrapper class TypeSyntax needed. There are several open feature requests to add wrapping functionality to Jackson e.g. https://github.com/FasterXML/jackson-databind/issues/512
Fortunately polymorphism is supported in Jackson with #JsonTypeInfo and #JsonSubTypes annotations.
Wrapper class should look like:
public class TypeSyntax {
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "identifierType")
private GenerateTypeBase identifierTypeValues;
// getters and setters (omitted for brevity)
}
GenerateTypeBase is the common parent class
#JsonSubTypes({
#JsonSubTypes.Type(value = GenerateType1.class, name = "Type1"),
#JsonSubTypes.Type(value = GenerateType2.class, name = "Type2"),
})
public abstract class GenerateTypeBase {
private String name;
private String age;
// getters and setters (omitted for brevity)
}
In this different children classes will instantiated based on the identifierType property.
The children must extend this base class:
public class GenerateType2 extends GenerateTypeBase {
// additional properties
}
In a short test it will be:
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
GenerateType2 a = new GenerateType2();
a.setName("Foo");
a.setAge("13");
TypeSyntax w = new TypeSyntax();
w.setIdentifierTypeValues(a);
String json = mapper.writeValueAsString(w);
System.out.println(json);
}
and the output:
{
"identifierTypeValues":
{
"name":"Foo",
"age":"13"
},
"identifierType":"Type2"
}
Deserialization
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String input = "{\"identifierTypeValues\": \"name\":\"Foo\",\"age\":\"13\"},\"identifierType\":\"Type2\"}";
TypeSyntax w = mapper.readValue(new StringReader(input), TypeSyntax.class);
assertAll(
() -> assertEquals(GenerateType2.class, o.getIdentifierTypeValues().getClass()),
() -> assertEquals("13", o.getIdentifierTypeValues().getAge())
);
}
If you want more flexibility you can write custom (de)serializer and / or custom resolver. Using custom TypeIdResolver that will possible to convert identifiers to types programmatically instead of using "key-value pairs" in #JsonSubTypes

Jackson - DTO int to String conversion

Working on a REST client that calls another server which returns the following object:
public class ObjectOriginal {
private int id;
private String name;
// constructor/getters/setters
}
I need to obfuscate the id. To do so I'm using an already existing service that transforms the id into a unique generated String so that the person calling my service doesn't know the REAL id but can still request info about it with the unique string.
So I'm basically trying to return to the caller this object:
public class ObjectNew {
private String id;
private String name;
// constructor/getters/setters
}
Do I need to have a copy of ObjectOriginalDTO + create a ObjectNew DTO + create a mapper to go from one to the other.
Or can I configure Jackson to deserialize the id field as a String and not an int?
You can do this using your own Serializer/Deserializer.
You have to implement your Serializer/Deserializer that will extends respectively BeanSerializerModifier/BeanDeserializerModifier and configuring your Module with them for instance Or use the annotation base solution as explained in this tutorial, there are plenty of references on the web for such a thing. then you'll have more controlle over the way to map your id.
If you don't want to have custom deserializer you can have:
public class ObjectNewDto {
private String id;
private String name;
// constructor/getters/setters
}
and another object:
public class ObjectOriginal {
private int id;
private String name;
// construxtor/getters/settes
}
Now after validating ObjectNewDto you can map it via your obfuscator service into ObjectOriginal , then validate this Object original and so on...

How to alias attributes in XStream with annotations?

I have the following piece of code
#XStreamAlias("Pa")
public class Pa {
#XStreamAsAttribute
private String ms;
#XStreamAsAttribute
private String co;
#XStreamAsAttribute
private String house;
#XStreamAsAttribute
private String street;
// Getters and Setters
}
I want my attributes names to be different from the variable names when my XML is constructed.
I know I can do it to classes with the following annotation
#XStreamAlias("ExampleClass")
private ExClass exClass;
The above code will result in a tag with the name
<ExampleClass/>
However, I cannot find any annotation that changes the name of the attribute without creating a separate tag.
What I want is the following:
<Pa milliseconds="" co =""/>
But using
#XStreamAlias("Milliseconds")
private String ms;
is creating a new tag with the given name. It no longer stays an attribute of the tag.
Does such an annotation exist? I need to do it only using annotations, not at runtime using Java code.
Thank you for your time.
You should use both annotations:
#XStreamAlias("Pa")
public class Pa {
#XStreamAsAttribute
#XStreamAlias("Milliseconds")
String ms = "test";
public static void main(String[] args) {
XStream xStream = new XStream();
xStream.ignoreUnknownElements();
xStream.processAnnotations(Pa.class);
String xml = xStream.toXML(new Pa());
System.out.println(xml);
}
}
output:
<Pa Milliseconds="test"/>

Is there a better way to implement HashMap<String, List<HashMap<String, List<Details>>>>?

I need to create json response in the following format:
{"responseCode":"00",
"responseMessage":"Success",
"planList":[
{"category":"category1",
"details":...}
{"category":"category2",
"details":...}
{"category":"category3",
"details":...}
]}
I came up with HashMap<String, List<HashMap<String, List<Details>>>>, but I feel there should be a better way to do this. Please help.
Thanks in advance.
I think you need to create classes with needed fields. For example:
class MyResponse {
private String responseCode;
private String responseMessage;
private List<Category> categories;
}
class Category {
private String category;
private String details;
}
It will increase readability.
You could write classes for the different entities in your list.
For example a class Response:
class Response {
private String responseCode;
private String responseMessage;
private List<Category> categories;
//....
}
and a class Category:
class Category {
private String categoryName;
private List<Details>
//...
}
This should work with different json-libraries like Gson or Jackson.
You need to create separate classes for each model element and than collect full response from those clases, e.g.
class Category {...}
...
another classes staff
...
class Response {...}
where Response - final response class;

Categories

Resources