How to pass different constructors as response in java - java

Response.java
public class Response{
private String mobileNo;
private String contractId;
private String sim;
private String imei;
public Response(String mobileNo, String contractId){
this.mobileNo = mobileNo;
this.contractId = contractId;
}
public Response(String mobileNo, String contractId, String sim,
String imei, String identificationType) {
this.mobileNo = mobileNo;
this.contractId = contractId;
this.sim = sim;
this.imei = imei;
this.identificationType = identificationType;
}
//Getter and Setter
}
MainEx.java
public class MainEx{
Response response = null;
public Response response(){
String mobileNo = null;
String contractId = null;
String sim = null;
String imei = null;
if(something){
response= new IVRAccountDetailsRs("777","4545");
}
else{
response= new IVRAccountDetailsRs("777","4545","sim","imei");
}
return response;
}
}
When if statement call return response as
{ "mobileNo" = "777";
"contractId" = "4545";
"sim"= null;
"imei" = null;
}
But I want to get the response as bellow,
When calling if statement
Need to remove other two values.
{ "mobileNo" = "777";
"contractId" = "4545";
}
If contractId and mobileNo null then output should be
{ "mobileNo" = null;
"contractId" = null;
}
When calling else statement
{ "mobileNo" = "777";
"contractId" = "4545";
"sim"= "sim";
"imei" = "imei";
}
if all values null
{ "mobileNo" = null;
"contractId" = null;
"sim"= null;
"imei" =null;
}
Used Jackson version is 2.4.1
What can I do about this?

If the version of SpringBoot is less than 1.3, it can only be handled programmatically
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class Response {
///~
}
Spring boot can be configured directly from 1.3 in the application.properties file
spring.jackson.default-property-inclusion=non_null
Official documentation for the jacksong configuration
you can use #JsonInclude(JsonInclude.Include.NON_NULL) on sim and imei, Not on the whole class
public class Response{
private String mobileNo;
private String contractId;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
public Response(String mobileNo, String contractId){
this.mobileNo = mobileNo;
this.contractId = contractId;
}
public Response(String mobileNo, String contractId, String sim,
String imei, String identificationType) {
this.mobileNo = mobileNo;
this.contractId = contractId;
this.sim = sim;
this.imei = imei;
this.identificationType = identificationType;
}

What you ask it's not possible to manage just with serialization.
I suggest to edit Response class, removing the field that don't want send when they are null.
Then create another class that extends Response, that have the other 2 fields.
At this point you can instantiate which one you want based on your condition and return anyway as a Response object.
public class SimpleResponse {
String mobileNo;
String contractId;
.....getters setters
}
public class FullResponse extends SimpleResponse {
String sim;
String imei;
....getter and setters
}

If you use jackson then add this:
#JsonInclude(JsonInclude.Include.NON_NULL) before field.
public class Response{
private String mobileNo;
private String contractId;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
}

For jackson serializers:
You can use annotation over your class, to skip serializing null values:
#JsonInclude(Include.NON_NULL)
public class Response{...}
Or add a parameter to your ObjectMapper configuration:
mapper.setSerializationInclusion(Include.NON_NULL);
This may be a duplicate.
UPDATE:
You can also annotate properties.
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
This way other properties will serialize null values, but those two will not be serialized with null value.

Add this annotation just above the getter of sim and imei
#JsonInclude(Include.NON_NULL)
With Jackson > 1.9.11 and < 2.x use
#JsonSerialize
annotation to do that:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
For the version above 2:
#JsonInclude(JsonInclude.Include.NON_NULL)

Related

I'm recieving "Error while extracting response for type" when I try to return the JSON as an Object. How can I solve this?

I'm doing an API that consumes an external API (https://swapi.dev/), but I'm receving this error when I try to return the JSON converted to Object.
I'm trying to solve this for almost 12 hours without any success x_x
Error while extracting response for type [class [Lcom.starwarsapi.filmsapi.model.FilmModel;] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `[Lcom.starwarsapi.filmsapi.model.FilmModel;` from Object value (token `JsonToken.START_OBJECT`);
FilmController:
#RestController
#RequestMapping("/films")
public class FilmController {
#Autowired
private FilmService filmService;
#GetMapping
public List<FilmModel> getAllFilms() {
List<FilmModel> response = filmService.getAllFilms();
return response;
}
FilmModel:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class FilmModel {
private FilmResultModel[] results;
}
FilmResultModel
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class FilmResultModel {
private String title;
#JsonProperty("episode_id")
private Integer episodeId;
#JsonProperty("opening_crawl")
private String description;
private String director;
private String producer;
#JsonProperty("release_date")
private String releaseData;
private String[] characters;
private String[] planets;
private String[] starships;
private String[] vehicles;
private String[] species;
private String created;
private String edited;
private String url;
FilmService:
public interface FilmService {
public List<FilmModel> getAllFilms();
}
FilmServiceImpl:
#Service
public class FilmServiceImpl implements FilmService {
#Value("${external.api.url}")
private String filmBaseUrl;
#Autowired
private RestTemplate restTemplate;
#Override
public List<FilmModel> getAllFilms() {
FilmModel[] result = restTemplate.getForObject(filmBaseUrl, FilmModel[].class);
List<FilmModel> films = Arrays.asList(result);
System.out.println(films);
return films;
}
PS¹: external.api.url = https://swapi.dev/api/films/?format=json
PS²: When I return getAllFilms as String, the program works:
#Override
public String getAllFilms() {
String result = restTemplate.getForObject(filmBaseUrl, String.class);
System.out.println(result);
return result;
}
But I need it to return as an object because later I'll try to create a PUT method to change the description of the movie.
try using FilmModel result = restTemplate.getForObject(filmBaseUrl, FilmModel.class);
FilmModel is just the outer wrapper object and contains the list of films.

How work with immutable object in mongodb and lombook without #BsonDiscriminator

I tried to work with immutable objects in MongoDB and Lombok. I found a solution to my problem but it needs to write additional code from docs but I need to used Bson annotations and create a constructor where describes fields via annotations. But if I user #AllArgsConstructor catch exception: "Cannot find a public constructor for 'User'" because I can't use default constructor with final fields. I think i can customize CodecRegistry correctly and the example will work correctly but I couldn't find solution for it in docs and google and Stackoverflow.
Is there a way to solve this problem?
#Data
#Builder(builderClassName = "Builder")
#Value
#BsonDiscriminator
public class User {
private final ObjectId id;
private final String name;
private final String pass;
private final String login;
private final Role role;
#BsonCreator
public User(#BsonProperty("id") final ObjectId id,
#BsonProperty("name") final String name,
#BsonProperty("pass") final String pass,
#BsonProperty("login") final String login,
#BsonProperty("role") final Role role) {
this.id = id;
this.name = name;
this.pass = pass;
this.login = login;
this.role = role;
}
#AllArgsConstructor
public enum Role {
USER("USER"),
ADMIN("ADMIN"),
GUEST("GUEST");
#Getter
private String value;
}
public static class Builder {
}
}
Example for MongoDB where I create, save and then update users:
public class ExampleMongoDB {
public static void main(String[] args) {
final MongoClient mongoClient = MongoClients.create();
final MongoDatabase database = mongoClient.getDatabase("db");
database.drop();
final CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
final MongoCollection<User> users = database.getCollection("users", User.class).withCodecRegistry(pojoCodecRegistry);
users.insertMany(new ExampleMongoDB().getRandomUsers());
System.out.println("Before updating:");
users.find(new Document("role", "ADMIN")).iterator().forEachRemaining(
System.out::println
);
System.out.println("After updating:");
users.updateMany(eq("role", "ADMIN"), set("role", "GUEST"));
users.find(new Document("role", "GUEST")).iterator().forEachRemaining(
System.out::println
);
}
public List<User> getRandomUsers() {
final ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 15; i++) {
users.add(
User.builder()
.login("log" + i)
.name("name" + i)
.pass("pass" + i)
.role(
(i % 2 == 0) ? User.Role.ADMIN : User.Role.USER
).build()
);
}
return users;
}
}
This should work (it worked for me):
#Builder(builderClassName = "Builder")
#Value
#AllArgsConstructor(onConstructor = #__(#BsonCreator))
#BsonDiscriminator
public class User {
#BsonId
private final ObjectId _id;
#BsonProperty("name")
private final String name;
#BsonProperty("pass")
private final String pass;
#BsonProperty("login")
private final String login;
#BsonProperty("role")
private final Role role;
}
Then in lombok.config add these (in your module/project directory):
lombok.addLombokGeneratedAnnotation=true
lombok.anyConstructor.addConstructorProperties=true
lombok.copyableAnnotations += org.bson.codecs.pojo.annotations.BsonProperty
lombok.copyableAnnotations += org.bson.codecs.pojo.annotations.BsonId
Also piece of advice, keep _id if you are going to use automatic conversion to POJOs using PojoCodec, which will save a lot of trouble.

Jackson: deserialize with Builder along with standard setters/getters?

Is it possible with Jackson to deserialize json with Builder pattern as well as with default setter and getter approach?
My object is created with Builder that covers only required (final) fields, but I have non-final fields with some values as well that need to be deserialized with setters.
Here is the sample that throws an exception in an attempt to deserialize it with:
new ObjectMapper().readValue(json, Foo.class);
json - json representation serialized with default Jackson serializer, like:
objectMapper.writeValueAsString(foo);
class
#Getter
#Setter
#ToString
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonDeserialize(builder = Foo.Builder.class)
public class Foo {
private final String key;
private final Long user;
private final String action;
private final String material;
private final String currency;
private Foo(String key, Long user, String action, String material, String currency) {
this.key = key;
this.user = user;
this.action = action;
this.material = material;
this.currency = currency;
}
public static class Builder {
private String key;
private Long user;
private String action;
private String material;
private String currency;
#JsonProperty("key")
public Foo.Builder withKey(String key) {
this.key = key;
return this;
}
#JsonProperty("user")
public Foo.Builder withUser(Long user) {
this.user = user;
return this;
}
#JsonProperty("action")
public Foo.Builder withAction(String action) {
this.action = action;
return this;
}
/// other 'with' setters....
}
#JsonProperty("state")
private int state;
#JsonProperty("stat")
private String stat;
#JsonProperty("step")
private String step;
}
The exception it throws like :
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "state" (class com.Foo$Builder), not marked as
ignorable (5 known properties: "key", "user", "action", "material",
"currency",])
If not possible what workaround is the cheapest?
Two things that are suspicious:
You are willing to use the builder inside the Foo class. In that case you should correct the specification
(SessionData.Builder.class is not correct in that case).
You are indeed trying to use an external builder. In this case you should remove or at least mark as ignorable the inner builder, this seems to be the reason of the excetpion you are getting.
In both cases you should make sure the final method to get the Foo instance is called build() otherwise you should annotate the builder with a #JsonPOJOBuilder(buildMethodName = "nameOfMethod", withPrefix = "set").

Java object not populated from json request for inner class

Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)

mapper.readValue() return null value (Jackson API)

I have one JSON object which I am trying to read from Jackson API Object Mapper.
{
"ddt_id":"605",
"ddt_batch_code":"5769005b-e8f0-4ae8-8971-1c59ac1f02fd",
"keyword":"ADP",
"keyword_operation":"and",
"keyword_extract_match":"F",
"search_in":"name",
"filter_type":"entity,others",
"category":"2,3,5",
"gender":"",
"date_year":"",
"date_month":"",
"date_day":"",
"country":"",
"search_filter_uuid":"570bd722-315c-40b3-b2d6-4522ac1f02fd",
"ddt_qsk_question":"0",
"search_for":"all",
"search_category":"2,3,5",
"search_includes_name":"T",
"search_includes_profile_notes":"F",
"search_for_person":"F",
"search_for_entity":"T",
"search_for_others":"T",
"search_from_module":"DDMT.V.2.20",
"client_id":667,
"ip_address":"52.23.94.13",
"search_requester_id":false,
"search_requester_name":false,
"batch_id":"5769005b-e8f0-4ae8-8971-1c59ac1f02fd",
"person_query_index":4,
"company_query_index":4,
"is_ongoing":1
}
The Class I used to read this JSON in Object is :
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class SswltSearchParams {
#JsonProperty("batch_id")
private UUID batchId;
#JsonProperty("country")
private String country;
#JsonProperty("criteria_id")
private String id;
#JsonProperty("date_day")
private Integer day;
#JsonProperty("date_month")
private Integer month;
#JsonProperty("date_year")
private Integer year;
#JsonProperty("gender")
private String gender;
#JsonProperty("keyword")
private String keyword;
#JsonProperty("keyword_exact_match")
private String keywordExactMatch;
#JsonProperty("keyword_operation")
private String keywordOperation;
#JsonProperty("search_category")
private String searchCategory;
#JsonProperty("search_for")
private String searchFor;
#JsonProperty("search_for_anti_corruption")
private String searchForAntiCorruption;
#JsonProperty("search_for_entity")
private String searchForEntity;
#JsonProperty("search_for_others")
private String searchForOthers;
#JsonProperty("search_for_person")
private String searchForPerson;
#JsonProperty("search_for_watchlist")
private String searchForWatchlist;
#JsonProperty("search_includes_name")
private String searchIncludesName;
#JsonProperty("search_includes_profile_notes")
private String searchIncludesProfileNotes;
#JsonProperty("update_only")
private String updateOnly;
// getters and setters
}
When I am trying to place this JSON in Onject, I am not getting any error but I am getting NULL value.
try {
SswltMigrationCollection sswltSearchParams = mapper.readValue(searchCriteria.getScrCriteria(), SswltSearchParams.class);
} catch (IOException e) {
return null;
}
Why I am getting this sswltSearchParams as null? Please Help.
Your JSON can be parsed into a SswltSearchParams instance without any problems. The following code works fine:
String json = "{\"ddt_id\":\"605\",\"ddt_batch_code\":\"5769005b-e8f0-4ae8-8971-1c59ac1f02fd\",\"keyword\":\"ADP\",\"keyword_operation\":\"and\",\"keyword_extract_match\":\"F\",\"search_in\":\"name\",\"filter_type\":\"entity,others\",\"category\":\"2,3,5\",\"gender\":\"\",\"date_year\":\"\",\"date_month\":\"\",\"date_day\":\"\",\"country\":\"\",\"search_filter_uuid\":\"570bd722-315c-40b3-b2d6-4522ac1f02fd\",\"ddt_qsk_question\":\"0\",\"search_for\":\"all\",\"search_category\":\"2,3,5\",\"search_includes_name\":\"T\",\"search_includes_profile_notes\":\"F\",\"search_for_person\":\"F\",\"search_for_entity\":\"T\",\"search_for_others\":\"T\",\"search_from_module\":\"DDMT.V.2.20\",\"client_id\":667,\"ip_address\":\"52.23.94.13\",\"search_requester_id\":false,\"search_requester_name\":false,\"batch_id\":\"5769005b-e8f0-4ae8-8971-1c59ac1f02fd\",\"person_query_index\":4,\"company_query_index\":4,\"is_ongoing\":1}";
ObjectMapper mapper = new ObjectMapper();
SswltSearchParams sswltSearchParams = mapper.readValue(json, SswltSearchParams.class);
Not sure why the SswltMigrationCollection class came into play.

Categories