This is the first version of my code :
public class ListSchedule implements ListInterface {
private ArrayList<Schedule> list;
private String cookie;
public ListSchedule() {
this.list = new ArrayList<Schedule>();
}
public ArrayList<Schedule> getList() {
return list;
}
}
In another class, I made this call :
protected final ListSchedule parse(String jsonString)
throws CustomException {
ListSchedule list = new ListSchedule();
JSONArray schedulesArray;
try {
// Convert the response to a JSONObject
JSONObject json = new JSONObject(jsonString);
try {
int errorCode = json.getInt("error");
// Check if there is no error from FilBleu server
if (errorCode > 0) {
throw new CustomException(
CustomException.ERROR_FILBLEU,
"DataAccessObject", "Server error "
+ json.getInt("subError"));
}
try {
String cookie = json.getString("cookie");
list = new ListSchedule(cookie);
} catch (JSONException e) {
throw new CustomException(CustomException.JSON_FORMAT,
"DataAccessObject", "No cookie value");
}
schedulesArray = json.getJSONArray("schedules");
// NullPointerException with the line below
Log.d("DAO", list.getList().toString());
parseSchedulesArray(list, schedulesArray);
} catch (JSONException e) { // Unable to get the error code
throw new CustomException(CustomException.JSON_FORMAT,
"DataAccessObject", "Bad JSON format ("
+ e.getMessage() + ")");
}
} catch (JSONException e) { // Unable to convert response
throw new CustomException(CustomException.JSON_FORMAT,
"DataAccessObject", "Bad JSON format ("
+ e.getMessage() + ")");
}
return list;
}
then I had a NullPointerException from the line Log.d("DAO", list.getList().toString());. So I tried another solution. As you can see, the only difference is the initialization of the list property :
public class ListSchedule implements ListInterface {
private ArrayList<Schedule> list = new ArrayList<Schedule>();
private String cookie;
public ListSchedule() {
}
public ArrayList<Schedule> getList() {
return list;
}
}
and the NullPointerException was never thrown again...
I don't really understand the difference between the two ways of initializing the list property. Can somebody give me a hint please ?
I am speculating that the following constructor exists in your code base :
public ListSchedule(String cookie) {
this.cookie = cookie;
}
and what you need is the following:
public ListSchedule(String cookie) {
this.cookie = cookie;
this.list = new ArrayList<Schedule>();
}
This is further validated by the invocation of this line in your program:
list = new ListSchedule(cookie);
Notice how you don't initialize the list in the second constructor. Also you start by invoking the default constructor, but you later reassign the pointer to the object into what gets created from the String constructor of ListSchedule.
You code is calling this constructor:
list = new ListSchedule(cookie);
Which to me, does not call the one that initializes your ArrayList<Schedule> and that explains the NullReferenceException
Related
I am reading JAVAX response using readEntity() method but I am getting following stacktrace :
java.lang.IllegalStateException: Entity input stream has already been closed.
at org.glassfish.jersey.message.internal.EntityInputStream.ensureNotClosed(EntityInputStream.java:225) ~[jersey-common.jar:?]
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:832) ~[jersey-common.jar:?]
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785) ~[jersey-common.jar:?]
at the line
Map<String, Map> mapEntityFromResponse = res.readEntity(Map.class);
Here is my code
public Output getClaimsFromAPI(#NonNull final Input xyzInput)
throws PermanentException, TransientException {
final Response res = fetchHealBeamServiceResponse(webTarget, xyzInput);
Object respondentMapObject;
Map<String, Map> mapEntityFromResponse = res.readEntity(Map.class);
if (mapEntityFromResponse != null) {
respondentMapObject = mapEntityFromResponse.get(ServiceConstants.MAP_KEY);
return getOutputFromResponseMap(respondentMapObject, xyzInput);
} else {
throw new RuntimeException("The response returned does not contain map");
}
}
private Response fetchHealBeamServiceResponse(WebTarget healBeamTarget,
Input xyzInput)
throws PermanentException, TransientException {
Response res = null;
try {
res = healBeamTarget
.path(HealBeamServiceConstants.GET_CUSTOMER_PATH)
.register(Configurator.getSoaOpNameFeatureForCustomerResource())
.resolveTemplate(ServiceConstants.ID, xyzInput.getId())
.request(MediaType.APPLICATION_JSON_TYPE)
.property(HealBeamServiceConstants.SERVICE_KEY, SOA_SERVICE_NAME)
.property(HealBeamServiceConstants.OPERATION_KEY, SOA_OP_NAME_GET_CUSTOMER)
.acceptLanguage(java.util.Locale.getDefault())
.get();
if (Response.Status.REQUEST_TIMEOUT.getStatusCode() == res.getStatusInfo().getStatusCode()) {
throw new TransientException("Request timed out with status" + res.getStatusInfo().getStatusCode());
} else if (Response.Status.OK.getStatusCode() != res.getStatusInfo().getStatusCode()) {
log.error("Some Error"):
}
return res;
} catch (RuntimeException e) {
throw new PermanentException("Unexpected Exception Occured, Exception Message " + e.getMessage());
} finally {
if (res != null) {
res.close();
}
}
}
You are closing your response in finally right before it gets returned, that is the reason, why you can't read from it in your calling method getClaimsFromAPI().
Just to demonstrate: What do you think the method main() posted below would print?
public class NewApp {
public static void main(String[] args) {
Person p = demonstrate();
System.out.println(p.name);
}
public static Person demonstrate(){
Person person = new Person();
try {
person.name = "name set in try";
return person;
} catch (Exception ex) {
throw ex;
} finally {
person.name = "name set in finally";
}
}
}
class Person {
public String name;
}
The problem is this adapter is giving the error although i have pass the Object array to it.(Read the methods belows then you will find what i want to know from you guys)
This method declares a List of private class objects. Then return that list of object to onPostExecute method.
private class DownloadXmlTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
return loadXmlFromNetwork(urls[0]);
} catch (IOException e) {
return "I/O exception ae hy";
} catch (XmlPullParserException e) {
return "XML pull parser ke exception ae hy";
}
}
#Override
protected void onPostExecute(List<StackOverflowXmlParser.Entry> result) {
//Log.d(TAG,result.toString());
ArrayAdapter<String> adapter;
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,result);
setListAdapter(adapter);
}
private Object loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
InputStream stream = null;
// Instantiate the parser
StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
List<StackOverflowXmlParser.Entry> entries = null;
String title = null;
String url = null;
String summary = null;
try {
stream = downloadUrl(urlString);
entries = stackOverflowXmlParser.parse(stream);
} finally {
if (stream != null) {
stream.close();
}
}
for (StackOverflowXmlParser.Entry entry : entries)
{
Log.d(TAG, entry.link + " /" + entry.title);
}
return entries;
}
I think it should be onPostExecute(List<StackOverflowXmlParser.Entry> result)
And you AsyncTask should be
extends AsyncTask<smth, smth, List<StackOverflowXmlParser.Entry> >
ArrayAdapter<String> requires that you provide it a String[] or a List<String>. You are trying to pass in Object[], which is neither String[] nor List<String>. And, it would appear that you are really trying to populate the ListView with a list of StackOverflowXmlParser.Entry objects, which are not String objects.
My guess is that the right answer is for you to create an ArrayAdapter<StackOverflowXmlParser.Entry> instead of an ArrayAdapter<String>.
Regardless, you need to ensure that the data type in your declaration (String in ArrayAdapter<String>) matches the data type in your constructor parameter that supplies the data to be adapted.
I'm trying to retrieve some data from my Db (I'm using SQLite) using DAO
public class ClassSectionDAO implements IClassSectionDAO{
#Override
public void selectAllClassSection() {
d = new DBManager();
sqliteQuery = new SqliteQueries();
d.executeQuery(sqliteQuery.selectAllFrom("classSection"));
try{
while(d.getResultSet().next()){
ClassSection classSection = new ClassSection();
classSection.setClassSectionId(d.getResultSet().getString("classSectionId"));
classSection.setSchoolClassCode(d.getResultSet().getString("schoolClassCode"));
classSection.setClassSectionNumber(d.getResultSet().getInt("classSectionNumber"));
classSection.setClassSectionAvailability(d.getResultSet().getString("classSectionAvailability"));
classSectionList.add(classSection);
System.out.println("classSectionList: " + classSectionList);
}
}
catch(Exception e){
Logger.getLogger(ClassSectionDAO.class.getName()).log(Level.SEVERE, null, e);
classSectionList = null;
}
finally{
d.closeDatabaseConnection();
}
}
}
All I'm getting is a list of objects like
classSectionList: [entities.classSection.ClassSection#19ccf6d, entities.classSection.ClassSection#1faf0e7, entities.classSection.ClassSection#1cf8409]
What should I do in order to get the values instead?
PS: If you want to see more code, let me know
I think you just made a typo, as you already said in your question: I get a list of Objects (of type ClassSection). That's clear because you print the list of Objects.
If you want to do it in the while loop (print immediately the value for every result), just change the last line in the loop to:
System.out.println("classSectionList: " + classSection.getSchoolClassCode());
If you want to print the values of all results (after all results are processed), just add Michaƫl's solution after the wile loop.
for(ClassSection c : classSectionList) {
System.out.println(c.getSchoolClassCode());
// print other attributes
}
EDIT :
Firt solution :
public class ClassSectionDAO implements IClassSectionDAO{
#Override
public void selectAllClassSection() {
d = new DBManager();
sqliteQuery = new SqliteQueries();
d.executeQuery(sqliteQuery.selectAllFrom("classSection"));
try{
while(d.getResultSet().next()){
ClassSection classSection = new ClassSection();
classSection.setClassSectionId(d.getResultSet().getString("classSectionId"));
classSection.setSchoolClassCode(d.getResultSet().getString("schoolClassCode"));
classSection.setClassSectionNumber(d.getResultSet().getInt("classSectionNumber"));
classSection.setClassSectionAvailability(d.getResultSet().getString("classSectionAvailability"));
classSectionList.add(classSection);
// Solution of ProgrammingIsAwsome
System.out.println("classSectionList: " + classSection.getSchoolClassCode());
}
}
catch(Exception e){
Logger.getLogger(ClassSectionDAO.class.getName()).log(Level.SEVERE, null, e);
classSectionList = null;
}
finally{
d.closeDatabaseConnection();
}
}
}
Second solution :
public class ClassSectionDAO implements IClassSectionDAO{
#Override
public void selectAllClassSection() {
d = new DBManager();
sqliteQuery = new SqliteQueries();
d.executeQuery(sqliteQuery.selectAllFrom("classSection"));
try{
while(d.getResultSet().next()){
ClassSection classSection = new ClassSection();
classSection.setClassSectionId(d.getResultSet().getString("classSectionId"));
classSection.setSchoolClassCode(d.getResultSet().getString("schoolClassCode"));
classSection.setClassSectionNumber(d.getResultSet().getInt("classSectionNumber"));
classSection.setClassSectionAvailability(d.getResultSet().getString("classSectionAvailability"));
classSectionList.add(classSection);
}
// Print the list after the while
for(ClassSection c : classSectionList) {
System.out.println(c.getSchoolClassCode());
// print other attributes
}
}
catch(Exception e){
Logger.getLogger(ClassSectionDAO.class.getName()).log(Level.SEVERE, null, e);
classSectionList = null;
}
finally{
d.closeDatabaseConnection();
}
}
}
I have this class
public static class SomeClass {
public SomeClass(String field) {
this.field = field;
}
private final String field;
public String getField() {
return field;
}
}
I have also this test (edited)
#Test
public void testStringifyMapOfObjects() {
Map<String, SomeClass> original = Maps.newTreeMap();
original.put("first", new SomeClass("a"));
original.put("second", new SomeClass("b"));
String encoded = JsonUtil.toJson(original);
Map<String, SomeClass> actual = JsonUtil.fromJson(encoded, Map.class);
Assert.assertEquals("{'first':{'field':'a'},'second':{'field':'b'}}", encoded.replaceAll("\\s", "").replaceAll("\"", "'"));
Assert.assertEquals(original.get("first"), actual.get("first"));
}
The test fails with
junit.framework.AssertionFailedError: expected:<eu.ec.dgempl.eessi.facade.transport.test.TestToolTest$SomeClass#6e3ed98c> but was:<{field=a}>
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.failNotEquals(Assert.java:277)
at junit.framework.Assert.assertEquals(Assert.java:64)
at junit.framework.Assert.assertEquals(Assert.java:71)
at eu.ec.dgempl.eessi.facade.transport.test.TestToolTest.testStringifyMapOfObjects(TestToolTest.java:90)
Can I make json to properly serialize objects as the values of the map or should I use something else?
edited
public class JsonUtil {
private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(JsonUtil.class);
public static <T> String toJson(T data) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(Feature.INDENT_OUTPUT, true);
try {
return mapper.writeValueAsString(data);
} catch (IOException e) {
LOG.warn("can't format a json object from [" + data + "]", e);
return null;
}
//
// return Json.stringify(Json.toJson(data));
}
public static <T> T fromJson(String description, Class<T> theClass) {
try {
JsonNode parse = new ObjectMapper().readValue(description, JsonNode.class);
T fromJson = new ObjectMapper().treeToValue(parse, theClass);
return fromJson;
} catch (JsonParseException e) {
// throw new RuntimeException("can't parse a json object of type " + theClass.getName() + " from [" + description + "]", e);
LOG.warn("can't parse a json object from [" + description + "]", e);
return null;
} catch (JsonMappingException e) {
// throw new RuntimeException("can't parse a json object of type " + theClass.getName() + " from [" + description + "]", e);
LOG.warn("can't parse a json object from [" + description + "]", e);
return null;
} catch (IOException e) {
// throw new RuntimeException("can't parse a json object of type " + theClass.getName() + " from [" + description + "]", e);
LOG.warn("can't parse a json object from [" + description + "]", e);
return null;
}
}
}
You are running into a problem related to Java generics. To summarize, when deserializing data into a non-reifiable type (aka a type for which actual type information is not available at runtime) you need to use a supertype token. You can get more detail about what a supertype token is (and why you need to use one) by reading these SO posts:
Pass parameterized type to method as argument
Error using Jackson and JSON
Deserialize JSON to ArrayList using Jackson
And also from the Jackson documentation:
Data Binding With Generics
TypeReference Javadoc
The basic problem is that when you use a typical generic object, the actual type parameters for the object aren't available at runtime. Therefore Jackson doesn't know which actual class to instantiate and deserialize your data into.
The easiest way to get around the problem would be adding an overload to your JSON utility class, that accepts a type reference (as opposed to a Class<T>). For example:
public static <T> T fromJson(String json, TypeReference<T> typeRef) {
if(json == null || typeRef == null) return null;
return new ObjectMapper().readValue(json, typeRef);
}
To be used as such:
Map<String, SomeClass> actual = JsonUtil.fromJson(
encoded,
new TypeReference<Map<String, SomeClass>>(){});
I discovered that the simplest solution is to create a "container" class that will contain the map. This is working probably because the container has enough type details for the map, as opposed to the case when a map is used directly.
public static class SomeClass {
private final String field;
private SomeClass() {
this("wrong");
}
public SomeClass(String field) {
this.field = field;
}
public String getField() {
return field;
}
#Override
public String toString() {
return "SomeClass[" + field + "]";
}
}
public static class SomeClassContainer {
private final Map<String, SomeClass> all = Maps.newTreeMap();
public Map<String, SomeClass> getAll() {
return all;
}
}
After this ... the updated test is
#Test
public void testStringifyMapOfObjects() {
SomeClassContainer original = new SomeClassContainer();
original.getAll().put("first", new SomeClass("a"));
original.getAll().put("second", new SomeClass("b"));
String encoded = JsonUtil.toJson(original);
System.out.println(encoded);
SomeClassContainer actual = JsonUtil.fromJson(encoded, SomeClassContainer.class);
System.out.println(ObjectUtils.toString(actual));
Assert.assertEquals("{'all':{'first':{'field':'a'},'second':{'field':'b'}}}", encoded.replaceAll("\\s", "").replaceAll("[\"]", "'"));
Assert.assertEquals("class eu.ec.dgempl.eessi.facade.transport.test.TestToolTest$SomeClass", actual.getAll().get("first").getClass().toString());
Assert.assertEquals(original.getAll().get("first").toString(), actual.getAll().get("first").toString());
Assert.assertEquals(original.getAll().get("second").toString(), actual.getAll().get("second").toString());
}
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).