Convert JSON to JAVA object using Jackson keeps running, no error - java

I'm trying to convert a JSON (from REST API) to a Java Object using Jackson.
But when I run this code. Netbeans keeps running but nothing changes..
My hash works fine, so I don't think my URL is wrong..
Is my mapper wrongly configured? I can't find a solution..
public Beheerder meldAan(String email, String wachtwoord){
if (email == null || wachtwoord == null) {
throw new IllegalArgumentException("Gebruikersnaam en wachtwoord moeten worden ingevuld.");
}
Beheerder beheerder = null;
try {
List<Beheerder> beheerders = repo.geefAlleBeheerders();
if (controlleerBeheerder(beheerders, email)) {
throw new IllegalArgumentException("Gebruikersnaam is verkeerd ingevuld.");
}
String hash = sha256(wachtwoord);
//URL jsonUrl = new URL("https://studservice.hogent.be/auth/" + email + "/" + hash);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
beheerder = mapper.readValue(jsonUrl, Beheerder.class);
if (beheerder == null) {
throw new IllegalArgumentException("Gelieve een correct wachtwoord in te geven");
}
return beheerder;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
return beheerder;
}
public class Beheerder {
private int beheerderId;
private String faculteit;
private String naam;
private String foto;
private String type;
private String voornaam;
private String email;
private boolean isHoofdbeheerder;
public Beheerder(String f, String fm, String foto, String type, String vm, String email){
this.faculteit = f;
this.type = type;
this.naam = fm;
this.foto = foto;
this.voornaam = vm;
this.email = email;
} //With some getters and setters..

I assume there is a problem retrieving the data from the remote server.
You should separate these concerns: Have one method fetching the data and one method deserializing it. You can test the JSON mapping then separately, f.e. with a String input from a unit test or a separate main class.
Try loading the JSON manually from your browser or command line with curl/wget as well. (Could be a firewall issue which would explain that it takes so long instead of immediate failure.)

In the picture you can see the variables when I debugged it..
Debug session
String hash = sha256(wachtwoord);
String json = "{\"FACULTEIT\":\"FBO\",\"NAAM\":\"De Durpel\",\"BASE64FOTO\":\"zezz//\",\"TYPE\":\"student\",\"VOORNAAM\":\"Kas\",\"EMAIL\":\"kas.dedurpel.s3007#student.ho‌​gent.be\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
beheerder = mapper.readValue(json, Beheerder.class);
if (beheerder == null) {
throw new IllegalArgumentException("Gelieve een correct wachtwoord in te geven");
}
My 'Beheerder' object stays null when I do it manually.
But It is a problem retrieving the data I guess!

Related

How to parse multiple JSON objects from a file in Java using URL

I have multiple JSON objectsavailable inside a text file and I am trying to get data from each of them to get some data and store it in my database. The following is a sample of the data I have :
{"address":"4565 S Wayside Dr","categories":["Other Textile Goods","Textile Manufacturers"],"city":"Houston","country":"US","dateAdded":"2016-11-17T22:36:43Z","dateUpdated":"2017-09-12T14:29:52Z","keys":["us/tx/houston/4565swaysidedr/-1836686262"],"latitude":"29.6981","longitude":"-95.3212","name":"Radium Textiles LLC","phones":["7136901081"],"postalCode":"77087","province":"TX","sourceURLs":["http://www.citysearch.com/profile/607780624/houston_tx/radium_textiles_llc.html"],"id":"AVwdH8-KkufWRAb52ixf"}
{"address":"6104 Donoho St","categories":["Wholesale Textile Brokers","Textile Brokers"],"city":"Houston","country":"US","dateAdded":"2017-03-26T19:08:42Z","dateUpdated":"2017-03-26T19:08:42Z","imageURLs":["http://images1.citysearch.net/assets/guide/images/logo_citysearch_130x25.gif"],"keys":["us/tx/houston/6104donohost/-214331342"],"latitude":"29.677891","longitude":"-95.324173","name":"T A Textiles","phones":["7136452800"],"postalCode":"77033","province":"TX","sourceURLs":["http://www.superpages.com/bp/houston-tx/t-a-textiles-L2170967950.htm","http://houston.citysearch.com/profile/647921770/houston_tx/t_a_textiles.html"],"id":"AVwdbMI6IN2L1WUfvriy"}
{"address":"4544 S Pinemont Dr","categories":["Other Fabricated Textile Product Manufacturers","Textile Manufacturers","Other Textile Goods"],"city":"Houston","country":"US","dateAdded":"2016-11-17T22:33:12Z","dateUpdated":"2017-09-12T14:29:50Z","keys":["us/tx/houston/4544spinemontdr/-1836686262"],"latitude":"29.8369","longitude":"-95.5160","name":"Radium Textiles LLC","neighborhoods":["Fairbanks/ Northwest Crossing , Northwest Houston"],"phones":["7136901390"],"postalCode":"77041","province":"TX","sourceURLs":["http://www.citysearch.com/profile/694636660/houston_tx/radium_textiles_llc.html","http://www.yellowpages.com/houston-tx/mip/radium-textiles-456243882?lid=456243882"],"websites":["http://api.citygridmedia.com/content/places/v2/click?q=9YKflVKbY9NauPJdMy0B1gS1IhB4xv4EWw0zDoT-UWc_izWF3zs5PKGdfOHubWrvM0QwDCYwbOH2fdLi0dK5xArULcksCCbfR-WWAz9xD1AmGVAQZIom4U3n5R4DuRC8WJCtvJcNItEKoCSfzwapuGnmwGnHDpEGYXGjnN4u8zXqkiimSHFf4_dbqGRbVgNJczcRYGsO7BQjsEDjdlUTJ3CxVQB3K1438yd7WPe-AAAIJEq588kBWNDLbak0Vs-EUxvQmWKBKxWI5ahci9eDn5KNvXpHpqZUL_e0UVacwelpEs92aC0Q2f_N0ZyiviGOHw8dOG3WIXM3rnMIStdm3v06ddF7lICNJl77Z6Y_mtMiylGr2EYGE_lU-dhl6pZnJ92MqQhlZpOjEubWZv1Bd95b8A-INOGKto848V3VdJNGPJwFN_DkdeWGF8YMvDWgew1xs3RSeBeHcBqFzLqQkDbgIllvuxl9VON3HBMwPYjMZ0kqzhi02JRzW0rO_gItNZKuHfHb3rNrWctuJQ2Qvup-kEiLHf5Hya_5KCAgn6uOStAioAXszLKlglJqFMNQE39j6ieFhMg&placement=listing_profile&cs_user=unknown&cs_session=88473fea2af4b100b0e7993b2eafa4bedbe4234c"],"id":"AVwczWsPkufWRAb5zLcG"}
{"address":"7085 Alameda Ave","categories":["Other Textile Goods","Textile Manufacturers","Textile Finishers","Wholesale Textiles"],"city":"El Paso","country":"US","dateAdded":"2017-06-27T05:29:45Z","dateUpdated":"2017-09-06T17:24:47Z","keys":["us/tx/elpaso/7085alamedaave/-266489986"],"latitude":"31.7550","longitude":"-106.3926","name":"Midwest Textile Co","phones":["9158811790"],"postalCode":"79915","province":"TX","sourceURLs":["http://www.citysearch.com/profile/620236204/el_paso_tx/midwest_textile_co.html"],"id":"AVzoBujQLD2H7whiXdiR"}
I am trying to parse it as follows:
InputStream resourceInputStream = context.getResourceAsStream("/WEB-INF/jsp/modules/data/20180427-businesses.txt");
String jsonString = IOUtils.toString(resourceInputStream, "UTF-8");
JSONObject json = (JSONObject) JSONSerializer.toJSON( jsonString );
String address = json.getString("address");
But since the data is not a single JSON string, this is not working correctly. Also, the data I have is not inside an array and that has made things more difficult for me. I also tried to create a Java Class with similar variables and tried to map the JSON string directly to that class, and it was also not working for me.
InputStream resourceInputStream = context.getResourceAsStream("/WEB-INF/jsp/modules/data/20180427-businesses.txt");
String jsonString = IOUtils.toString(resourceInputStream, "UTF-8");
ObjectMapper mapper = new ObjectMapper();
BusinessDataImportHB records = mapper.readValue(jsonString, BusinessDataImportHB.class);
Where:
public class BusinessDataImportHB
{
private List<BusinessRecord> records;
public List<BusinessRecord> getRecords() {
return records;
}
public void setRecords(List<BusinessRecord> records) {
this.records = records;
}
}
and
public class BusinessRecord {
private String address;
private List<String> categories;
private String city;
private String country;
private Date dateAdded;
private Date dateUpdated;
private List<String> keys;
private String latitude;
private String longitude;
private String name;
private List<String> phones;
private String postalCode;
private String province;
private List<String> websites;
private String id;
I cannot change the format of the data. What is the best approach I could use to parse the data and get individual records?
If each JSON Object is in one line you could read the file line by line.
try (Stream<String> stream = Files.lines(Paths.get("..."))) {
stream.forEach(line -> {
JSONObject json = (JSONObject) JSONSerializer.toJSON(line);
String address = json.getString("address");
});
}
If your records are on a line-by-line basis and you have a large file, you may want to consider reading and parsing line by line. You can use a try-with-resources block to ensure no memory leaks from unclosed resources.
String pathname = "/home/william/test.txt"; // your file
try (Scanner sc = new Scanner(new FileInputStream(new File(pathname)))) {
while (sc.hasNextLine()) {
JSONObject json = (JSONObject) JSONSerializer.toJSON(sc.nextLine());
// TODO do something with it
}
} catch (Exception e) {
// TODO
}

How to make a correct Json Deserialization to a Java Object?

I really need help here, im Deserializing the next json:
{
"name":"myname",
"userID":"12345",
"password":"sha1passwordASDESFSGSD",
"active":"1",
"profile":"2",
"job":"Manager"
}
Im using Jersey to create webService, when i recive the json i recive it as a InputStream
Also i tried with a String
#POST
#Path("user/in/")
#Produces("application/json")
public String InsertUser(InputStream inStr)
{
String line = null, res = "POST 200 > ";
BufferedReader br = new BufferedReader(new InputStreamReader(inStr));
try {
while ((line = br.readLine()) != null) {
System.out.println(line);
res += line;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
UserInformation user = new Gson().fromJson(res, UserInformation.class);
System.out.println("All done");
System.out.println(user.getName());
} catch (Exception e) {
System.out.println("Error al convertir jo object " + e.getCause() + e.getMessage());
}
return "POST 200 > ";
}
I tried using a InputStreamReader:
#POST
#Path("user/in/")
#Produces("application/json")
public String InsertUser(InputStream inStr)
{
try {
InputStreamReader isr = new InputStreamReader(inStr);
UserInformation user = new Gson().fromJson(isr, UserInformation.class);
System.out.println("All done");
System.out.println(user.getName());
} catch (Exception e) {
System.out.println("Error al convertir jo object " + e.getCause() + e.getMessage());
}
return "POST 200 > ";
}
Neither of those codes work. They don't throw an exception or print "All done".
When i debug the object, user doesn't appear in the variables menu.
In my experience, is because an error is happening in the line UserInformation user = new Gson().fromJson(isr, UserInformation.class);
But i cant see which one is.
My UserInformation Class is the next
public class UserInformation {
private String name;
private String userID;
private String password;
private String active;
private String profile;
private String job;
// Methods removed for brevity
}
I am assuming you are using Google gson. Here is my answer:
#Post
#Path("user/in")
#Produces(MediaType.APPLICATION_JSON)
public Response InsertUser(string json){
JsonElement jsonElement = new JsonParser().parse(json);
JsonObject object = jsonElement.getAsJsonObject();
String name = object.getAsJsonPrimitive("name").getAsString();
int userID = object.getAsJsonPrimitve("userID").getAsInt();
String password = object.getAsJsonPrimitive("password").getAsString();
String job = object.getAsJsonPrimitive("job").getAsString();
int active = object.getAsJsonPrimitve("active").getAsInt();
int profile = object.getAsJsonPrimitve("profile").getAsInt();
return Response.status(Response.Status.OK).entity("all done").build();
}
I already find the solution, the problem was that i was receiving a InputStream,
following its recommendations the solution code is:
#POST
#Path("users/in/")
#Produces(MediaType.APPLICATION_JSON)
public String InsertUser(String json)
{
try{
UserInformation user = new Gson().fromJson(json, UserInformation.class);
String name = user.getName();
String userID = user.getUserID();
String password = user.getPassword();
String job = user.getJob();
String active = user.getActive();
String profile = user.getProfile();
}catch(Exception e){
System.out.println(Response.status(500).entity(e.getCause() + e.getMessage()).build().toString());
return Response.status(500).entity(e.getCause() + e.getMessage()).build().toString();
}
}

Returned List<Object> in JSON from C# and read in java application

here is the asmx method:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String mtdImporteUsuario()
{
JavaScriptSerializer ser = new JavaScriptSerializer();
List<UsuarioBO> usuarios = new List<UsuarioBO>();
try
{
query = new Procedimientos().QSelectAllUsers();
ds = new ConexionBD().mtdEjecutaQuery_DS(query, "Usuarios");
foreach (DataRow dr in ds.Tables[0].Rows)
{
usuarios.Add(new UsuarioBO
{
O_COD = 1,
O_MENSAJE = "OK",
NId_usuario = Convert.ToInt32(dr["idusuario"]),
SCod_cuenta = dr["cuenta"].ToString(),
SCod_password = dr["password"].ToString(),
NNum_rut = Convert.ToInt32(dr["num_RutUsuario"]),
SDv_rut = dr["dv_RutUsuario"].ToString(),
SGls_nombre = dr["primer_nombre"].ToString(),
SGls_apellido_paterno = dr["apellido_paterno"].ToString(),
SGls_apellido_materno = dr["apellido_materno"].ToString(),
NId_perfil = Convert.ToInt32(dr["idperfil"])
});
}
}
catch (Exception ex)
{
throw ex;
}
return ser.Serialize(usuarios);
}
and the response is:
<?xml version="1.0" encoding="UTF-8"?>
<string xmlns="http://tempuri.org/">[{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":4,"NId_perfil":1155,"NNum_rut":10584082,"SGls_nombre":"Juan","SCod_cuenta":"jancan","SCod_password":"12345","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Ancan","SGls_apellido_materno":"","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":13,"NId_perfil":1155,"NNum_rut":10584080,"SGls_nombre":"Marco","SCod_cuenta":"msuazo","SCod_password":"msuazo","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Suazo","SGls_apellido_materno":"","SDv_rut":"2"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":15,"NId_perfil":1122,"NNum_rut":10584082,"SGls_nombre":"Administrador","SCod_cuenta":"gallendes","SCod_password":"joi7jiuml","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"","SGls_apellido_materno":"tratos","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":16,"NId_perfil":1155,"NNum_rut":11072809,"SGls_nombre":"Juan","SCod_cuenta":"jchavez","SCod_password":"claudia","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Chavez","SGls_apellido_materno":"","SDv_rut":"3"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":17,"NId_perfil":1155,"NNum_rut":11994419,"SGls_nombre":"German","SCod_cuenta":"gcabrera","SCod_password":"210372","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Cabrera","SGls_apellido_materno":"","SDv_rut":"8"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":20,"NId_perfil":145,"NNum_rut":17203522,"SGls_nombre":"Jose Francisco","SCod_cuenta":"jfhurtado","SCod_password":"123","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Hurtado","SGls_apellido_materno":"Ruiz-Tagle","SDv_rut":"1"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":21,"NId_perfil":1122,"NNum_rut":10584082,"SGls_nombre":"Roberto","SCod_cuenta":"tratos","SCod_password":"tratos","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Puga","SGls_apellido_materno":"Y.","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":22,"NId_perfil":1155,"NNum_rut":18084387,"SGls_nombre":"Nazareno","SCod_cuenta":"nfigueroa","SCod_password":"supervisor","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Figueroa","SGls_apellido_materno":"","SDv_rut":"6"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":23,"NId_perfil":1155,"NNum_rut":10584082,"SGls_nombre":"Jose Luis","SCod_cuenta":"jlramirez","SCod_password":"jose","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Ramirez","SGls_apellido_materno":"","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":24,"NId_perfil":1155,"NNum_rut":10584082,"SGls_nombre":"Manuel","SCod_cuenta":"mcorrea","SCod_password":"manuel","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Correa","SGls_apellido_materno":"","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":25,"NId_perfil":144,"NNum_rut":1,"SGls_nombre":"Administrador ","SCod_cuenta":"nubix","SCod_password":"admin","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"","SGls_apellido_materno":"","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":26,"NId_perfil":146,"NNum_rut":5777261,"SGls_nombre":"Franco","SCod_cuenta":"fnieri","SCod_password":"fnieri","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Nieri","SGls_apellido_materno":"","SDv_rut":"1"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":27,"NId_perfil":1122,"NNum_rut":17248311,"SGls_nombre":"Camila Fernanda Valentina","SCod_cuenta":"cflores","SCod_password":"nene2302","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"Flores","SGls_apellido_materno":"Haub","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":28,"NId_perfil":1,"NNum_rut":1,"SGls_nombre":"nombreDermo","SCod_cuenta":"dermo","SCod_password":"dermo","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"ApellidoPat","SGls_apellido_materno":"ApellidoMat","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":29,"NId_perfil":1,"NNum_rut":1,"SGls_nombre":"dime","SCod_cuenta":"dimetu","SCod_password":"dimeyo","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"tu","SGls_apellido_materno":"yo","SDv_rut":"9"},{"O_COD":1,"O_MENSAJE":"OK","NId_usuario":30,"NId_perfil":2,"NNum_rut":1,"SGls_nombre":"no","SCod_cuenta":"dimeyo","SCod_password":"dimetu","SFoto":"","SFotoOri":"","SGls_apellido_paterno":"mb","SGls_apellido_materno":"re","SDv_rut":"9"}]</string>
How can i read that response from android?
Android has built-in capabilities of manipulating JSON through the classes of the package org.json: http://developer.android.com/reference/org/json/package-summary.html
If you, instead, want to create a List of Usuario objects, in these cases, I usually use something like Jackson http://jackson.codehaus.org/ or gson https://code.google.com/p/google-gson/
In both cases you have to create a Java Bean, i.e. a class Usuario.java with all the fields private and all the getters and setters public, such as:
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() { return name; }
}
and you can deserialise, using jackson with:
String string = [{"name": "nameA"}, {"name":"nameB"}];
ObjectMapper mapper = new ObjectMapper();
Usuario[] usuarios = mapper.fromString(string, User[].class);
In your case you should first remove the first line.

Jackson deserialization error handling

My problem is fairly simple : I have the following simple class:
public class Foo {
private int id = -1;
public void setId(int _id){ this.id = _id; }
public int getId(){ return this.id; }
}
And I am trying to process following JSON:
{
"id": "blah"
}
Obviously, there is a problem here ("blah" cannot be parsed to an int)
Formerly, Jackson throws something like org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.lang.Integer from String value 'blah': not a valid Integer value
I agree with this, but I'd like to register something somewhere allowing to ignore this type of mapping errors.
I tried with a DeserializationProblemHandler registered (see here) but it seems to only work on unknown properties and not deserialization problems.
Have you any clue on this issue?
I succeeded to solve my problem, thanks to Tatu from Jackson ML.
I had to use custom non blocking deserializers for every primitive types handled in Jackson.
Something like this factory :
public class JacksonNonBlockingObjectMapperFactory {
/**
* Deserializer that won't block if value parsing doesn't match with target type
* #param <T> Handled type
*/
private static class NonBlockingDeserializer<T> extends JsonDeserializer<T> {
private StdDeserializer<T> delegate;
public NonBlockingDeserializer(StdDeserializer<T> _delegate){
this.delegate = _delegate;
}
#Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
try {
return delegate.deserialize(jp, ctxt);
}catch (JsonMappingException e){
// If a JSON Mapping occurs, simply returning null instead of blocking things
return null;
}
}
}
private List<StdDeserializer> jsonDeserializers = new ArrayList<StdDeserializer>();
public ObjectMapper createObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule customJacksonModule = new SimpleModule("customJacksonModule", new Version(1, 0, 0, null));
for(StdDeserializer jsonDeserializer : jsonDeserializers){
// Wrapping given deserializers with NonBlockingDeserializer
customJacksonModule.addDeserializer(jsonDeserializer.getValueClass(), new NonBlockingDeserializer(jsonDeserializer));
}
objectMapper.registerModule(customJacksonModule);
return objectMapper;
}
public JacksonNonBlockingObjectMapperFactory setJsonDeserializers(List<StdDeserializer> _jsonDeserializers){
this.jsonDeserializers = _jsonDeserializers;
return this;
}
}
Then calling it like this way (pass as deserializers only those you want to be non blocking) :
JacksonNonBlockingObjectMapperFactory factory = new JacksonNonBlockingObjectMapperFactory();
factory.setJsonDeserializers(Arrays.asList(new StdDeserializer[]{
// StdDeserializer, here, comes from Jackson (org.codehaus.jackson.map.deser.StdDeserializer)
new StdDeserializer.ShortDeserializer(Short.class, null),
new StdDeserializer.IntegerDeserializer(Integer.class, null),
new StdDeserializer.CharacterDeserializer(Character.class, null),
new StdDeserializer.LongDeserializer(Long.class, null),
new StdDeserializer.FloatDeserializer(Float.class, null),
new StdDeserializer.DoubleDeserializer(Double.class, null),
new StdDeserializer.NumberDeserializer(),
new StdDeserializer.BigDecimalDeserializer(),
new StdDeserializer.BigIntegerDeserializer(),
new StdDeserializer.CalendarDeserializer()
}));
ObjectMapper om = factory.createObjectMapper();
You might want to let your controller handle the problem by adding a method that handles this specific exception
#ExceptionHandler(HttpMessageNotReadableException.class)
#ResponseBody
public String handleHttpMessageNotReadableException(HttpMessageNotReadableException ex)
{
JsonMappingException jme = (JsonMappingException) ex.getCause();
return jme.getPath().get(0).getFieldName() + " invalid";
}
Of course, the line
JsonMappingException jme = (JsonMappingException) ex.getCause();
might throw a class cast exception for some cases but i haven't encountered them yet.
I have written a simple error handler which will give you some kind of error which you can return to user with bad request as status code. Use #JsonProperty required = true to get error related to missing properties. Jackson version 2.9.8.
public class JacksonExceptionHandler {
public String getErrorMessage(HttpMessageNotReadableException e) {
String message = null;
boolean handled = false;
Throwable cause = e.getRootCause();
if (cause instanceof UnrecognizedPropertyException) {
UnrecognizedPropertyException exception = (UnrecognizedPropertyException) cause;
message = handleUnrecognizedPropertyException(exception);
handled = true;
}
if (cause instanceof InvalidFormatException) {
InvalidFormatException exception = (InvalidFormatException) cause;
message = handleInvalidFormatException(exception);
handled = true;
}
if (cause instanceof MismatchedInputException) {
if (!handled) {
MismatchedInputException exception = (MismatchedInputException) cause;
message = handleMisMatchInputException(exception);
}
}
if (cause instanceof JsonParseException) {
message = "Malformed json";
}
return message;
}
private String handleInvalidFormatException(InvalidFormatException exception) {
String reference = null;
if (!exception.getPath().isEmpty()) {
String path = extractPropertyReference(exception.getPath());
reference = removeLastCharacter(path);
}
Object value = exception.getValue();
return "Invalid value '" + value + "' for property : " + reference;
}
private String handleUnrecognizedPropertyException(UnrecognizedPropertyException exception) {
String reference = null;
if (!exception.getPath().isEmpty()) {
String path = extractPropertyReference(exception.getPath());
reference = removeLastCharacter(path);
}
return "Unknown property : '" + reference + "'";
}
private String handleMisMatchInputException(MismatchedInputException exception) {
String reference = null;
if (!exception.getPath().isEmpty()) {
reference = extractPropertyReference(exception.getPath());
}
String property = StringUtils.substringBetween(exception.getLocalizedMessage(), "'", "'");
// if property missing inside nested object
if (reference != null && property!=null) {
return "Missing property : '" + reference + property + "'";
}
// if invalid value given to array
if(property==null){
return "Invalid values at : '"+ reference +"'";
}
// if property missing at root level
else return "Missing property : '" + property + "'";
}
// extract nested object name for which property is missing
private String extractPropertyReference(List<JsonMappingException.Reference> path) {
StringBuilder stringBuilder = new StringBuilder();
path.forEach(reference -> {
if(reference.getFieldName() != null) {
stringBuilder.append(reference.getFieldName()).append(".");
// if field is null means it is array
} else stringBuilder.append("[].");
}
);
return stringBuilder.toString();
}
// remove '.' at the end of property path reference
private String removeLastCharacter(String string) {
return string.substring(0, string.length() - 1);
}
}
and call this class object in global advice like this
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
String message = new JacksonExceptionHandler().generator.getErrorMessage(ex);
if(message == null){
return ResponseEntity.badRequest().body("Malformed json");
}
return ResponseEntity.badRequest().body(message);
}
Create a simple Mapper:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JSONProcessingErroMapper implements ExceptionMapper<InvalidFormatException> {
#Override
public Response toResponse(InvalidFormatException ex) {
return Response.status(400)
.entity(new ClientError("[User friendly message]"))
.type(MediaType.APPLICATION_JSON)
.build();
}
}
DeserializationProblemHandler now has a lot more methods, such as handleUnexpectedToken and handleWeird*Value. It should be able to handle anything one needs.
Subclass it, override methods you need, then add it to your ObjectMapper with addHandler(DeserializationProblemHandler h).

Convert object to JSON in Android

Is there a simple method to convert any object to JSON in Android?
Most people are using gson : check this
Gson gson = new Gson();
String json = gson.toJson(myObj);
public class Producto {
int idProducto;
String nombre;
Double precio;
public Producto(int idProducto, String nombre, Double precio) {
this.idProducto = idProducto;
this.nombre = nombre;
this.precio = precio;
}
public int getIdProducto() {
return idProducto;
}
public void setIdProducto(int idProducto) {
this.idProducto = idProducto;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Double getPrecio() {
return precio;
}
public void setPrecio(Double precio) {
this.precio = precio;
}
public String toJSON(){
JSONObject jsonObject= new JSONObject();
try {
jsonObject.put("id", getIdProducto());
jsonObject.put("nombre", getNombre());
jsonObject.put("precio", getPrecio());
return jsonObject.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
}
Might be better choice:
#Override
public String toString() {
return new GsonBuilder().create().toJson(this, Producto.class);
}
download the library Gradle:
implementation 'com.google.code.gson:gson:2.9.0'
To use the library in a method.
Gson gson = new Gson();
//transform a java object to json
System.out.println("json =" + gson.toJson(Object.class).toString());
//Transform a json to java object
String json = string_json;
List<Object> lstObject = gson.fromJson(json_ string, Object.class);
Spring for Android do this using RestTemplate easily:
final String url = "http://192.168.1.50:9000/greeting";
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Greeting greeting = restTemplate.getForObject(url, Greeting.class);
As of Android 3.0 (API Level 11) Android has a more recent and improved JSON Parser.
http://developer.android.com/reference/android/util/JsonReader.html
Reads a JSON (RFC 4627) encoded value as a stream of tokens. This
stream includes both literal values (strings, numbers, booleans, and
nulls) as well as the begin and end delimiters of objects and arrays.
The tokens are traversed in depth-first order, the same order that
they appear in the JSON document. Within JSON objects, name/value
pairs are represented by a single token.
The Kotlin way
val json = Gson().toJson(myObj)
Anyway, you know this
Gson gson = new Gson();
String json = gson.toJson(yourModelClassReference);
You might have forget to add #Expose

Categories