Return list of errors - java

I wan to return a list of errors using this Response object:
public class StringResponseDTO {
private String response;
public StringResponseDTO(String response) {
super();
this.response = response;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}
I use this code to generate errors:
List<FieldError> errors = result.getFieldErrors();
for (FieldError error : errors ) {
System.out.println ("Validation error in field: " + error.getObjectName()
+ "! Validation error message: " + error.getDefaultMessage()
+ "! Rejected value:" + error.getRejectedValue());
return ResponseEntity.ok(new StringResponseDTO(error.getField() + " " + error.getDefaultMessage()));
}
I want to return a list like this:
response: {
errors: [
field_name: message,
second_name: second_message
]
}
Do you know how I can modify the code? Probably I need add constructor?

response: {
errors: [
field_name: message,
second_name: second_message
]
}
You need to use the following classes to model the above json:
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
#JsonTypeName("response")
class StringResponseDTO {
private List<String> errors;
public StringResponseDTO(final List<String> errors) {
this.errors = errors;
}
public List<String> getErrors() {
return errors;
}
public void setErrors(final List<String> errors) {
this.errors = errors;
}
}
You can construct the response as:
List<String> errorsList = new ArrayList<>();
List<FieldError> errors = result.getFieldErrors();
for (FieldError error : errors ) {
System.out.println ("Validation error in field: " + error.getObjectName()
+ "! Validation error message: " + error.getDefaultMessage()
+ "! Rejected value:" + error.getRejectedValue());
errorsList.add(error.getField() + " " + error.getDefaultMessage());
}
return ResponseEntity.badRequest().body(new StringResponseDTO(errorsList));

Related

Uncaught SyntaxError: Unexpected end of JSON input at Function.parse [as parseJSON] (<anonymous>)

I've been getting this error. How can I fix it?
Error
Uncaught SyntaxError: Unexpected end of JSON input
at Function.parse [as parseJSON] ()
at Object. (:128:24)
at i (jquery.min.js:2)
at Object.fireWith [as resolveWith] (jquery.min.js:2)
at A (jquery.min.js:4)
at XMLHttpRequest. (jquery.min.js:4)
Screenshot of the error (transcribed here)
File asqBatch.jsp
When I click the button.
function genExcelRep() {
var param = "${urlExcelLink}?year=${batchData.year}&period=${batchData.period}&programId=${batchData.programId}&batchId=${batchData.batchId}";
repDialog = BootstrapDialog.show({
title: "Generating Report",
message: '<h1 style="text-align:center;vertical-align: middle;"><i class="fa fa-spinner fa-spin" style="font-size:40px;color:black"></i> 5%</h1>',
onshow: function(dialogRef) {
dialogRef.enableButtons(false);
dialogRef.setClosable(false);
$.ajax({
type: "POST",
url: param,
cache: false
})
.done(function(result) {
console.log(result);
var data = $.parseJSON(result);
alert(json.pid);
alert("done(function(result) 1");
dialogRef.setMessage(data.result);
alert("done(function(result) 2");
if(data.isSuccess) {
alert("if(data.isSuccess)");
if(data.result == "Session Timeout") {
alert("Session Timeout");
SessionTimeOutRedirect("${redirectLink}");
}
else {
alert("generateExcelReport jsp");
generateExcelReport(data);
}
}
else {
alert("else(data.isSuccess)");
dialogRef.enableButtons(true);
dialogRef.setClosable(true);
}
});
},
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
buttons: [{
label: 'Close',
action: function(dialogRef) {
dialogRef.close();
}
}]
});
}
Controller
model.addAttribute("urlExcelLink", "mainASQBatch/DownloadExcel.htm");
model.addAttribute("contGenExcelUrl", "mainASQBatch/contGenerateExcel.htm");
The #RequestMapping part
#RequestMapping(method = RequestMethod.POST, value="/DownloadExcel") //
public void DownloadExcel(#ModelAttribute("ResultASQDataVO") ResultASQBatchVO vo, ModelMap model, HttpServletRequest req, HttpSession session, HttpServletResponse res) {
logger.info("generateExcelReportPart1 year:" + vo.getYear() +
"," + vo.getPeriod() +
"," + vo.getProgramId() +
"," + vo.getBatchId());
ResultASQDataVO rec = new ResultASQDataVO(vo.getYear(),
vo.getPeriod(),
vo.getProgramId(),
vo.getBatchId());
if(CommonMethod.IsSessionTimeOut(session)) {
rec.setResult("Session Timeout");
rec.setSuccess(true);
}
else {
boolean isSuccess = false;
String result = "";
try {
logger.info("generateExcelReportPart1 1");
List<ResultASQDataVO> lstReport = resultASQDataSER.distinctWorkSheet(
new ResultASQDataVO(rec.getYear(),
rec.getPeriod(),
rec.getProgramId(),
rec.getBatchId()));
String arr = lstReport.toString();
rec.setListReports(String.join(";", arr));
logger.info("generateExcelReportPart1 2");
int cnt = lstReport.size() + 1;
String dirReports = ReportCommonMethod.getTempReportFolderWithTimeStamp(new File(context.getRealPath("/")));
rec.setDirPath(dirReports);
rec.setFiles("");
float noIncrement = 0f;
rec.setSuccess(isSuccess);
logger.info("generateExcelReportPart1 3");
if(CommonMethod.validate(rec.getListReports())) {
rec.setSuccess(true);
noIncrement = 100/(cnt);
logger.info("generateExcelReportPart1 4");
while(noIncrement*cnt>100) {
noIncrement -= 0.25;
}
isSuccess = true;
result = REPORT_GENERATE_RESULT.PROGRESS.getAlert(String.valueOf(Math.round(noIncrement)) + "%");
}
logger.info("generateExcelReportPart1 5");
rec.setCurrentProgress(noIncrement);
rec.setNoIncrement(noIncrement);
rec.setResult(result);
rec.setSuccess(isSuccess);
}
catch (SQLException e) {
logger.info("Localized Message: " + e.getLocalizedMessage());
logger.info("Exception Message: " + e.getMessage());
logger.info("Exception Cause: " + e.getCause());
e.printStackTrace();
e.printStackTrace();
}
}
}
The values in "rec.setResult(result)" should be shown in the module .jsp file.

Jackson error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token

Hey I have also problem here is my Json
[
{
"aimid": "12345"
},
{
"aimid": "333674"
},
{
"aimid": [
"4568999",
"6789345"
]
}]
and This is my Pojo class:-
#JsonProperty("aimid")
private String aimid;
public String getAimid() {
return aimid;
}
public void setAimid(String aimid) {
this.aimid = aimid;
}
I want to store aimid in pojo . When i am writing like above in my application i am getting error.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token.
From my understanding i am getting error because of Array element so anyone can suggest me how i can capture both thing if it is coming as String or It is coming as a Array String
The challenge is that in some cases "aimid" is a string value but in another case it is an array.
If you have control over the structure of the JSON then update the structure so that each element of the root array has ONE of the following structures:
String
{
"aimid": "333674"
}
OR array
{
"aimid": [
"4568999",
"6789345"
]
}
If you do not have control of the structure of the data you will need to parse it yourself and process it into your POJO.
Please see these 3 code examples that should illustrate how you can go about this approaches. :
public class MyPojo {
private List<String> aimid;
#JsonProperty("aimid")
public List<String> getAimid() {
return aimid;
}
#JsonProperty("aimid_array")
public void setAimid(final List<String> aimid) {
this.aimid = aimid;
}
#JsonProperty("aimid")
public void setAimid(final String aimid) {
this.aimid = Arrays.asList(aimid);
}
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.*;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Test;
public class UnitTest {
private static final Logger LOGGER = Logger.getLogger(UnitTest.class.getName());
public UnitTest() {
}
#Test
public void testOneAimId() throws IOException {
final String json = "[\n"
+ "{\n"
+ " \"aimid\": \"12345\"\n"
+ "},\n"
+ "{\n"
+ " \"aimid\": \"333674\"\n"
+ "}]";
final List<MyPojo> result = new ObjectMapper().readValue(json, new TypeReference<List<MyPojo>>() {
});
log(Level.SEVERE, LOGGER, "testOneAimId", result);
}
#Test
public void testListAimIds() throws IOException {
final String json = "[\n"
+ "{\n"
+ " \"aimid_array\": [\n" // HERE WE HAVE CHANGED THE JSON PROP NAME
+ " \"4568999\",\n"
+ " \"6789345\"\n"
+ " ]\n"
+ "}]";
final List<MyPojo> result = new ObjectMapper().readValue(json, new TypeReference<List<MyPojo>>() {
});
log(Level.SEVERE, LOGGER, "testListAimIds", result);
}
#Test
public void testMixed() throws IOException {
final String json = "[\n"
+ "{\n"
+ " \"aimid\": \"12345\"\n"
+ "},\n"
+ "{\n"
+ " \"aimid\": \"333674\"\n"
+ "},\n"
+ "{\n"
+ " \"aimid_array\": [\n" // HERE WE HAVE CHANGED THE JSON PROP NAME
+ " \"4568999\",\n"
+ " \"6789345\"\n"
+ " ]\n"
+ "}]";
final List<MyPojo> result = new ObjectMapper().readValue(json, new TypeReference<List<MyPojo>>() {
});
log(Level.SEVERE, LOGGER, "testMixed", result);
}
#Test
public void testMixed2() throws IOException {
final String json = "[\n"
+ "{\n"
+ " \"aimid\": \"12345\"\n"
+ "},\n"
+ "{\n"
+ " \"aimid\": \"333674\"\n"
+ "},\n"
+ "{\n"
+ " \"aimid\": [\n"
+ " \"4568999\",\n"
+ " \"6789345\"\n"
+ " ]\n"
+ "}]";
final JsonNode result = new ObjectMapper().readValue(json, JsonNode.class);
final ArrayList<String> arrayList = new ArrayList<>();
result.forEach((final JsonNode jsonNode) -> {
if (jsonNode.getNodeType() != JsonNodeType.OBJECT)
throw new IllegalArgumentException(jsonNode.toString());
final ObjectNode obj = (ObjectNode) jsonNode;
obj.forEach(o -> {
switch (o.getNodeType()) {
case ARRAY:
final ArrayNode array = (ArrayNode) o;
array.forEach(t -> arrayList.add(t.asText()));
break;
case STRING:
arrayList.add(o.asText());
break;
default:
throw new IllegalArgumentException(o.toString());
}
});
});
final MyPojo myPojo = new MyPojo();
myPojo.setAimid(arrayList);
log(Level.SEVERE, LOGGER, "myPojo", myPojo);
}
private void log(final Level level, final Logger logger, final String title, final Object obj) {
try {
if (title != null)
logger.log(level, title);
final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter();
logger.log(level, obj == null ? "null" : writer.writeValueAsString(obj));
} catch (final JsonProcessingException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
}

Java/Jackson Annotations: Mapping either an array or object?

If I can get either of the following JSON bodies as responses:
{
"error" : "some error",
"code": 123
}
or
[
{
"name" : "name",
"value" : "value"
},
{
"name" : "name",
"value" : "value"
}
]
Is there a way to map either of these response to below Java POJO using annotations ?
public class Response {
String error;
int code;
List<NameValuePair> nameValuePairs;
}
Out of the box, only the error response will deserialise. The issue is they are fundamentally different types - an object vs an array.
You can make it work with a custom module for jackson, as described here
One possible response is a JSON Object and other is a JSON Array. In that case it is not possible to create one POJO class to handle it. Also, these two payloads means to different things: one is SUCCESS and other is ERROR payloads. In that case I would use Facade design pattern to create extra layer and hide this complex logic there. It could look like below:
class ResponseDeserialiserFacade {
private final ObjectMapper mapper = new ObjectMapper();
public List<NameValuePair> deserialisePairs(String json) {
try {
return mapper.readValue(json, new TypeReference<List<NameValuePair>>() {
});
} catch (IOException e) {
try {
Error error = mapper.readValue(json, Error.class);
throw new RequestApiException(error, e);
} catch (IOException e1) {
throw new RequestApiException(Error.from("Can not parse: " + json), e1);
}
}
}
}
As you noticed I introduced new exception:
class RequestApiException extends RuntimeException {
private final Error error;
RequestApiException(Error error, Exception base) {
super(base);
this.error = error;
}
public Error getError() {
return error;
}
}
with Error class:
class Error {
private String error;
private String code;
public static Error from(String message) {
Error e = new Error();
e.error = message;
return e;
}
// getters, setters, toString
}
Now we can test it for SUCCESS and ERROR payloads:
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
public class JsonApp {
public static void main(String[] args) {
String success = "[\n" +
" {\n" +
" \"name\" : \"name\",\n" +
" \"value\" : \"value\"\n" +
" },\n" +
" {\n" +
" \"name\" : \"name\",\n" +
" \"value\" : \"value\"\n" +
" }\n" +
"]\n";
tryToParse(success);
String error = "{\n" +
" \"error\" : \"some error\",\n" +
" \"code\": 123\n" +
"}";
tryToParse(error);
}
private static void tryToParse(String json) {
ResponseDeserialiserFacade deserialiser = new ResponseDeserialiserFacade();
try {
List<NameValuePair> pairs = deserialiser.deserialisePairs(json);
System.out.println("SUCCESS: " + pairs);
} catch (RequestApiException e) {
System.out.println("ERROR: " + e.getError());
}
}
}
class NameValuePair {
private String name;
private String value;
// getters, setters, toString
}
Above code prints:
SUCCESS: [NameValuePair{name='name', value='value'}, NameValuePair{name='name', value='value'}]
ERROR: Error{error='some error', code='123'}
As you can see, we treated error message like as exception.

Android Retrofit 2 post request responses with name of response class

In my app I make post request to the server with a special code inside the body. Then I should get some information in the response. However, I always get the name of the response class.
My request code:
#POST("/accounts/login/vk-oauth2/")
Call<RegistrationProcessCodeResponse> postCode(#Body CodePostRequest code);
My ResponseClass:
public class RegistrationProcessCodeResponse {
private String message;
private String partial_token;
private String phase;
public String getMessage() {
return message;
}
public String getPartial_token() {
return partial_token;
}
public String getPhase() {
return phase;
}
public void setMessage(String message) {
this.message = message;
}
public void setPartial_token(String partial_token) {
this.partial_token = partial_token;
}
public void setPhase(String phase) {
this.phase = phase;
}
}
My request code:
HseAlumniApi hseAlumniApi = HseAlumniApi.retrofit.create(HseAlumniApi.class);
Call<RegistrationProcessCodeResponse> postComment = hseAlumniApi.postCode(codePostRequest);
postComment.enqueue(new Callback<RegistrationProcessCodeResponse>() {
#Override
public void onResponse(Call<RegistrationProcessCodeResponse> call, Response<RegistrationProcessCodeResponse> response) {
Log.d("myLogs", "String.valueOf(response.code())\n" + String.valueOf(response.code()));
Log.d("myLogs", "response.body().toString()\n" + response.body().toString());
if (response.isSuccessful()) {
Log.d("myLogs", "Request succeeded");
}
}
#Override
public void onFailure(Call<RegistrationProcessCodeResponse> call, Throwable t) {
Log.d("myLogs", "Request failed");
}
});
My logs:
D/myLogs: String.valueOf(response.code())
200
D/myLogs: response.body().toString()
com.example.vitaly.hsealumni.RegistrationProcessCodeResponse#498e7e7
D/myLogs: Request succeeded
Response Json:
{
"message": "email needed",
"partial_token": "231445d4fc5a4ed99dccb681942d5d7e",
"phase": 1
}
I really have no idea what to do, help please
public class RegistrationProcessCodeResponse {
private String message;
private String partial_token;
private String phase;
public RegistrationProcessCodeResponse() {
message = "";
partial_token = "";
phase = "";
}
// getters and setters
#Override
public String toString() {
return "RegistrationProcessCodeResponse{" +
"message='" + message + '\'' +
", partial_token='" + partial_token + '\'' +
", phase='" + phase + '\'' +
'}';
}
}

Iterate ArrayList

I want to know the best way to iterate this ArrayList, this ArrayList comes from a Response from an API, this is the ArrayList:
The problem is that i dont know how to get the "id" and the "value" from the loop,
i know the arraylist size but i dont have any idea how to print the "Keys" and "Values" from this Array
for(int i=1; i <= contacts.size(); i++) {
//Example System.out.print(contacts[i]->id);
//Example System.out.print(contacts[i]->contact_name) ;
//Example System.out.print(contacts[i]->numbers);
//Example System.out.print(contacts[i]->emails);
//I want to print id and value
//
}
In onResponse i call this fucntion for example:
ServerResponse resp = response.body();
functionExample((ArrayList) resp.getResponse());
The functionExample have an ArrayList as parameter.
This is my result from my resp.getResponse():
This is my json from the API:
{
"result": "success",
"message": "Lista de Contactos",
"response": [
{
"id": 1,
"contact_name": "EDIFICADORA JUANA",
"numbers": "{24602254,55655545}",
"emails": "{oipoa#gmaio.com,rst008#guan.com}"
},
{
"id": 2,
"contact_name": "LA MEJOR",
"numbers": "{25445877,25845877}",
"emails": "{AMEJOR#GMAIL.COM}"
}
]
}
I appreciate any help.
public void FunctionExample(ArrayList contacts) {
for(int i=0; i < contacts.size(); i++) {
LinkedTreeMap<String, Object> map = (LinkedTreeMap<String, Object>) contacts.get(i);
map.containsKey("id");
String id = (String) map.get("id");
map.containsKey("contact_name");
String contact_name = (String) map.get("contact_name");
map.containsKey("numbers");
String numbers = (String) map.get("numbers");
numbers.replace("{","").replace("}","");
map.containsKey("emails");
String emails = (String) map.get("emails");
emails.replace("{","").replace("}","");
Snackbar.make(getView(), id, Snackbar.LENGTH_LONG).show();
Snackbar.make(getView(), contact_name, Snackbar.LENGTH_LONG).show();
Snackbar.make(getView(), numbers, Snackbar.LENGTH_LONG).show();
Snackbar.make(getView(), emails, Snackbar.LENGTH_LONG).show();
}
}
Try this..It will give arrayList of id's
JSONObject object=new JSONObject(response);
JSONArray array= null;
try {
array = object.getJSONArray("response");
} catch (JSONException e) {
e.printStackTrace();
}
ArrayList<String> idArray=new ArrayList<>();
for(int i=0;i< array.length();i++)
{
idArray.add(getJSONObject(i).getString("id"));
}
Try this way if you are using ArrayList<TreeMap<String, String>> contacts;
for(TreeMap<String,String> contact : contacts){
String id = contact.getValue("id");
}
I would strongly encourage you to use e.g. Jackson to map your JSON response to a proper object. Consider following example:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JacksonTest {
private static final String JSON = "{\n" +
"\"result\": \"success\",\n" +
"\"message\": \"Lista de Contactos\",\n" +
"\"response\": [\n" +
" {\n" +
" \"id\": 1,\n" +
" \"contact_name\": \"EDIFICADORA JUANA\",\n" +
" \"numbers\": \"{24602254,55655545}\",\n" +
" \"emails\": \"{oipoa#gmaio.com,rst008#guan.com}\"\n" +
" },\n" +
" {\n" +
" \"id\": 2,\n" +
" \"contact_name\": \"LA MEJOR\",\n" +
" \"numbers\": \"{25445877,25845877}\",\n" +
" \"emails\": \"{AMEJOR#GMAIL.COM}\"\n" +
" }\n" +
" ]\n" +
"}";
#Test
public void testParsingJSONStringWithObjectMapper() throws IOException {
//given:
final ObjectMapper objectMapper = new ObjectMapper();
//when:
final Response response = objectMapper.readValue(JSON, Response.class);
//then:
assert response.getMessage().equals("Lista de Contactos");
//and:
assert response.getResult().equals("success");
//and:
assert response.getResponse().get(0).getId().equals(1);
//and:
assert response.getResponse().get(0).getContactName().equals("EDIFICADORA JUANA");
//and:
assert response.getResponse().get(0).getEmails().equals(Arrays.asList("oipoa#gmaio.com", "rst008#guan.com"));
//and:
assert response.getResponse().get(0).getNumbers().equals(Arrays.asList(24602254, 55655545));
}
static class Response {
private String result;
private String message;
private List<Data> response = new ArrayList<>();
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<Data> getResponse() {
return response;
}
public void setResponse(List<Data> response) {
this.response = response;
}
}
static class Data {
private String id;
#JsonProperty("contact_name")
private String contactName;
private String numbers;
private String emails;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public List<Integer> getNumbers() {
return Stream.of(numbers.replaceAll("\\{", "")
.replaceAll("}", "")
.split(","))
.map(Integer::valueOf)
.collect(Collectors.toList());
}
public void setNumbers(String numbers) {
this.numbers = numbers;
}
public List<String> getEmails() {
return Arrays.asList(emails.replaceAll("\\{", "")
.replaceAll("}", "")
.split(","));
}
public void setEmails(String emails) {
this.emails = emails;
}
}
}
In this example I used same JSON response you receive and jackson-core library (http://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core/2.8.9) for mapping String to a POJOs (instead of String you can use InputStream, byte[] etc.). There are two POJOs: Response and Data. Response aggregates a list of Data objects. Additionally, Data's getEmails() and getNumbers() methods parse your input String to a list of expected objects. For example if you call setNumbers("{24602254,55655545}") then getNumbers() will return a list of Integers (you can use any numeric type instead) like [24602254, 55655545].
Other suggestions are also valid, e.g. iterating over collection of TreeMaps or JSONObjects. In this example we limit our focus to deal with Java objects with specific types instead of dealing with primitives like Object class for example.
The final solution also depends on your runtime environment. In this case you will have to add jackson-core dependency - it makes more sense if your project already uses Jackson for other reasons.
If you are using Set< Map< String, String>> set;
set.stream().forEach(map -> {
System.out.print("Id:" + map.get("id") + "ContactName:" + map.get("contact_name"));
});
Try this loop to extract every value from ArrayList of yours
List<LinkedTreeMap> list = new ArrayList<LinkedTreeMap>(); //assign result from API to list
for(LinkedTreeMap<String,String> contact : list){
for(String id : contact.keySet()){
if(id.equalsIgnoreCase("id")){
System.out.println("ID: "+ contact.get(id));
}else if(id.equalsIgnoreCase("contact_name")){
System.out.println("Contact Name: "+ contact.get(id));
}else{ //if it is list of numbers or e-mails
String result = contact.get(id);
result = result.replaceAll("{|}", ""); //removing { }
String[] array = result.split(",");
System.out.println(id+": "); // this will be either numbers or e-mails
//now iterating to get each value
for(String s : array){
System.out.println(s);
}
}
}
}

Categories