I'm new to Spring and I'm having trouble consuming an API and serialising the Response to Java POJOs using Jackson. This the API endpoint I'm trying to consume.
This what my request looks like:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Authorization", "Bearer " + applicationProperties.getApiKey());
ArrayList<String> externalIds = new ArrayList<>();
externalIds.add(userId);
Map<String, Object> parameters = new HashMap<>();
parameters.put("external_ids", externalIds);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(parameters, headers);
ResponseEntity<ProfileExportDTO> response = this.restTemplate.postForEntity(url, request , ProfileExportDTO.class);
This is my POJO class (setters and getters removed for simplicity):
#JsonIgnoreProperties(ignoreUnknown = true)
public class ProfileExportDTO implements Serializable {
#JsonProperty("first_name")
private String firstname;
#JsonProperty("last_name")
private String lastname;
private String language;
private String email;
private String dob;
#JsonProperty("home_city")
private String city;
private String country;
private String phone;
#JsonProperty("time_zone")
private String timezone;
#JsonProperty("last_coordinates")
private float[] lastCoordinates;
private String gender;
#JsonProperty("total_revenue")
private float revenue;
private String attributed_campaign;
private String attributed_source;
private String attributed_adgroup;
private String push_subscribe;
private String email_subscribe;
My problem is that when this runs the produced object is null. Does anyone know why?
Related
I am trying to get a response message to a POJO class that has already been defined. However, I am getting null values for all the fields in the POJO class. I printed the json file and they are not null and I am wondering what is actually going. This is the response that I get.
I should get this VirtualAccountResponseDto(account_number=null, bank_code=null, unique_id=null, account_name=null, account_reference=null, bank_name=null, created_at=null, currency=null, id=null, account_status=null, customer=null)
This is the gson class that I printed to the console
+++++++++>>>>>>>>>{"data":{"account_number":"1110006278","bank_code":"000","unique_id":"KPY-VA-NEBOrKvKCmTSOJe","account_name":"James Bond","account_reference":"xyz163ath285","bank_name":"test","created_at":"2022-11-27T23:38:36.449Z","currency":"NGN","id":6268,"account_status":"active","customer":{"name":"James Bond","email":"hey#yxc.com"}},"message":"Virtual bank account created successfully","status":true}
This is what the POJO class looks like
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class VirtualAccountResponseDto {
#SerializedName("account_number")
private String account_number;
#SerializedName("bank_code")
private String bank_code;
private String unique_id;
private String account_name;
private String account_reference;
private String bank_name;
private String created_at;
private String currency;
private String id;
private String account_status;
private Customer customer;
This is the customer class
#Data
public class Customer {
private String email;
private String name;
}
Here is my code to convert from Json to POJO
Gson gson = new Gson();
String requestJson = gson.toJson(bankDto);
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Authorization", "Bearer "+KORAPAY_TOKEN);
headers.put("accept", "application/json");
HttpResponse<JsonNode> apiResponse = Unirest.post(KORAPAY_BASE_URL +
"virtual-bank-account")
.headers(headers)
.body(requestJson)
.asJson();
System.out.println(apiResponse.getBody());
JSONObject responseJson = apiResponse.getBody().getObject();
System.out.println("This is the response body" + apiResponse.getBody());
JsonParser jsonParser = new JsonParser();
JsonObject gsonObject = (JsonObject)jsonParser.parse(responseJson.toString());
System.out.println("+++++++++>>>>>>>>>" + gsonObject);
VirtualAccountResponseDto responseDTO = gson.fromJson(gsonObject,
VirtualAccountResponseDto.class);
System.out.println("I should get this " + responseDTO);
return responseDTO;
I have tried annotating the variable names with #Serializedname. I have also checked for case_senstivity issues. Also, I have rearranged the POJO fields in the order in which the JSON is returned and I still get the same null values
As #Marcono1234 pointed out, your DTO structure and JSON structures do not match.
I tried by modifying the structure of the DTO class to add a 'data' element and it works fine after that.
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class VirtualAccountResponseDto {
DataClass data; // <-- Added this class to match the JSON structure
}
#Data
class DataClass {
private String account_number;
private String bank_code;
private String unique_id;
private String account_name;
private String account_reference;
private String bank_name;
private String created_at;
private String currency;
private String id;
private String account_status;
private Customer customer;
}
#Data
class Customer {
private String email;
private String name;
}
Output after the change:
VirtualAccountResponseDto(data=DataClass(account_number=1110006278, bank_code=000, unique_id=KPY-VA-NEBOrKvKCmTSOJe, account_name=James Bond, account_reference=xyz163ath285, bank_name=test, created_at=2022-11-27T23:38:36.449Z, currency=NGN, id=6268, account_status=active, customer=Customer(email=hey#yxc.com, name=James Bond)))
I am trying to bind attributes that I get from calling controller in thymeleaf template to form and pass it as param in save method. here is my code:
#GetMapping("/alert/{id}")
public String getForm(Model model, #PathVariable(required = false, name = "id") String id) throws IOException {
final Datum datum = alertService.findById(id);
final List<ElasticAlert> elasticAlerts = ApplicationUtil.datumToElasticAlertModel(Collections.singletonList(datum), objectMapper);
if (elasticAlerts.size() != 1)
throw new IllegalArgumentException("Wrong id for editing data");
final ElasticAlert elasticAlert = elasticAlerts.stream().findFirst().orElseThrow(IllegalArgumentException::new);
elasticAlert.setParams(datum.getParams());
model.addAttribute("elasticAlert", elasticAlert);
return "update";
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Params {
private String aggType;
private String esQuery;
private Integer termSize;
private String thresholdComparator;
private Integer timeWindowSize;
private String timeWindowUnit;
private String groupBy;
private List<Integer> threshold;
private List<String> index;
private String timeField;
private String aggField;
private String termField;
private String level;
private String message;
private List<String> to;
private String subject;
private int size;
}
#Data
public class ElasticAlert {
private String id;
#NotBlank (message = "Event Name can not be blank")
#Size(max = 40, min = 5, message = "event name should be between 5-20 characters")
private String eventName;
#NotBlank (message = "Application Name can not be blank")
private String applicationName;
#NotBlank (message = "Email Subject can not be blank")
private String emailSubject;
#NotBlank (message = "Email to can not be blank")
#Pattern(regexp = "[a-zA-Z0-9]+#[abc|xyz]+goninv\\.com$", message = "incorrect email format")
private String emailTo;
#Valid
private List<ElasticException> elasticExceptionList = new ArrayList<>();
private String schedule;
private String notifyWhen;
private Params params;
}
I want to pass params object as it is to my form controller
<form method="post" th:action="#{/alert}" th:object="${elasticAlert}"
name="createAlertForm" id="createAlertForm" class="mb-3">
<input type="hidden" th:field="${elasticAlert.id}"/>
<input type="hidden" th:field="${elasticAlert.applicationName}"/>
<input type="hidden" th:valuetype="test.pojo.Params" th:field="${elasticAlert.params}" />
...
#PostMapping("/alert")
public String edit(#Valid ElasticAlert alert, BindingResult bindingResult, RedirectAttributes redirAttrs, Model model) throws IOException {
int i = 1;
final Params params = alert.getParams();
...
}
my params object is always null, it's not binding object to the input, is there any way to make it bind or an alternate way to approach this.
I am new to thymeleaf.
I guess the problem is in the first method,your request is #GetMapping("/alert/{id}"),but your thymeleaf is /alert,but the /alert request don't send messages.
I want to call another spring boot on spring boot
I read a lot of articles
Spring RestTemplate GET with parameters
Spring RestTemplate
Many more...
Temporary methods that I can currently use
final String uri = "http://127.0.0.1:8888/key";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(uri)
.queryParam("id", "1234")
.queryParam("model", "model")
.queryParam("name", "name")
.queryParam("description", "description")
.queryParam("status", 0)
.queryParam("mode", 1)
.queryParam("creationDate", "2021/05/24 12:34:56")
.queryParam("updatedDate", "2021/05/24 12:34:56");
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.PUT,
entity,
String.class);
I want to be able to use the class directly instead of slowly entering all the parameters
public class DataDto {
private String id;
private String model;
private String name;
private String description;
private int status;
private int mode;
private String creationDate;
private String updatedDate;
...
}
How can I use the entire class as a parameter at once?
I have tried many similar things, but there are no parameters on my server:
logger.info("getId:" + dataDto.getId());
final String uri = "http://127.0.0.1:8888/key";
RestTemplate restTemplate = new RestTemplate();
restTemplate.put(uri, DataDto.class, dataDto);
Try something like below.
Override toString() method for DataDto
#Override
public String toString() {
return String.format("id=%s&" +
"model=%s&" +
"name=%s&" +
"description=%s&" +
"status=%s&" +
"mode=%s&" +
"creationDate=%s&" +
"updatedDate=%s", id, model, name, description, status, mode,
creationDate, updatedDate);
}
Formulate URL like below,
final String uri = String.format("%s?%s", "http://127.0.0.1:8888/key", dataDto.toString())
I have model:
public class StudyModel {
#Id
private String ID;
private boolean isStable;
private String LastUpdate;
private MainTest test;
public static class MainTest {
private String test1;
private String test2;
}
}
I want to parse it to my model.
It works correctly but when it goes to MainTest where on json file I have couple values it fails and I have null on the rest of fields.
How I can deal with it?
public StudyModel getStudyDetails(String studyId){
RestTemplate restTemplate = new RestTemplate();
String url = URL + "studies/" + studyId;
ResponseEntity<String> serverResponse = restTemplate.getForEntity(url, String.class);
Gson g = new Gson();
String json = serverResponse.getBody();
StudyModel study = g.fromJson(json, StudyModel.class);
return study;
}
RestTemplate can handle deserialization for you
ResponseEntity<StudyModel> serverResponse = restTemplate.getForEntity(url, StudyModel.class);
StudyModel studyModel = serverResponse.getBody();
I started using Project Reactor recently and I can't work out how to work with nested streams. I want to update data of outer Mono with some data of inner Mono.
#GetMapping("/search")
public Mono<Github> combineGithubData() {
WebClient client = WebClient.create("https://api.github.com");
Mono<Github> data = client.get().uri(URI.create("https://api.github.com/users/autocorrectoff")).retrieve().bodyToMono(Github.class);
data = data.map(s -> {
client.get().uri(URI.create("https://api.github.com/users/Kukilej")).retrieve().bodyToMono(Github.class).map(m -> {
s.setXXX(m.getName());
return m;
});
return s;
});
return data;
}
The field XXX is always returned as null, although I have set it to a value from inner Mono. I'm pretty sure this would work in RxJs. How do I make this work with Project Reactor?
edit:
the code of the Github class
import lombok.*;
#Getter #Setter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class Github {
private String login;
private int id;
private String node_id;
private String avatar_url;
private String gravatar_id;
private String url;
private String html_url;
private String followers_url;
private String following_url;
private String gists_url;
private String starred_url;
private String subscriptions_url;
private String organizations_url;
private String repos_url;
private String events_url;
private String received_events_url;
private String type;
private boolean site_admin;
private String name;
private String company;
private String blog;
private String location;
private String email;
private String hireable;
private String bio;
private int public_repos;
private int public_gists;
private int followers;
private int following;
private String created_at;
private String updated_at;
private String XXX;
}
Your inner stream is not getting subscribed to. Either us flatMap, or better yet, use zip:
data
.zipWith(client.get().uri(...).retrieve().bodyToMono(Github.class))
.map(tuple2 -> {
//update tuple2.getT1() with m.getName() and return the updated tuple
return tuple2.mapT1(tuple2.getT1().setXXX(tuple2.getT2().getName()));
})
.map(tuple2 -> tuple2.getT1() //updated s);
zipWith() subscribes to the inner stream.