Boolean and array data binding using Jackson - java

I am trying deserialize the result returned from an API call. However, the result can either contain a Boolean or an array.
If the result is Boolean, the JSON content received in the response looks like:
{
"succeeded": true,
"version": 1.0
}
If the result is an array, the JSON received in the response looks like:
{
"succeeded": {
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
"fieldB": "2016-05-25T22:43:52Z",
"fieldC": "iws-user-cfg-proxy-beta",
"updated_at": "2016-05-25T22:43:52Z"
}
},
{
"get_info": {
"fieldA": "4551542",
"fieldB": "2016-07-27T22:26:27Z",
"fieldC": "silkRoot",
"updated_at": "2016-07-27T22:26:27Z"
}
}
]
},
"version": 1.0
}
I would like to read the value associated with the "succeeded" field. Is there a way I can handle this in the mapping class?
My current mapping class is as below:
public class ServResp {
public final static String TYPE1_EXCEPTION = "Type1Exception";
public final static String TYPE2_EXCEPTION = "Type2Exception";
public final int httpStatusCode;
public final boolan succeeded;
public final String version;
public final String exception;
public final String exceptionMessage;
private ServResp(Builder builder) {
this.httpStatusCode = builder.httpStatusCode;
this.succeeded = builder.succeeded;
this.version = builder.version;
this.exception = builder.exception;
this.exceptionMessage = builder.exceptionMessage;
}
public Builder modify() {
return new Builder(this);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((exception == null) ? 0 : exception.hashCode());
result = prime * result + ((exceptionMessage == null) ? 0 : exceptionMessage.hashCode());
result = prime * result + httpStatusCode;
result = prime * result + (succeeded ? 17 : 19);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ServResp other = (ServResp) obj;
if (exception == null) {
if (other.exception != null)
return false;
} else if (!exception.equals(other.exception))
return false;
if (exceptionMessage == null) {
if (other.exceptionMessage != null)
return false;
} else if (!exceptionMessage.equals(other.exceptionMessage))
return false;
if (httpStatusCode != other.httpStatusCode)
return false;
if (succeeded != other.succeeded)
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
public static class Builder {
private int httpStatusCode;
private boolean succeeded;
private String version;
private String exception;
private String exceptionMessage;
public Builder() {
}
public Builder(ServResp other) {
this.httpStatusCode = other.httpStatusCode;
this.version = other.version;
this.exception = other.exception;
this.exceptionMessage = other.exceptionMessage;
}
public Builder setHttpStatusCode(int httpStatusCode) {
this.httpStatusCode = httpStatusCode;
return this;
}
public Builder setSucceeded(boolean succeeded) {
this.succeeded = succeeded;
return this;
}
public Builder setVersion(String version) {
this.version = version;
return this;
}
public Builder setException(String exception) {
this.exception = exception;
return this;
}
public Builder setExceptionMessage(String exceptionMessage) {
this.exceptionMessage = exceptionMessage;
return this;
}
public ServResp build() {
return new ServResp(this);
}
}}
If I execute the program the way it is, I get the below error:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.boolean out of START_OBJECT token
Is there a way to get around this?

You could try changing the type of Builder.succeeded to Object, and then add some code to read it later. This sounds like a source of future bugs, but if you don't control the API then it may be your best shot.
public class Foo {
private Object overRiddenJsonType;
public Object getOverRiddenJsonType() {
return overRiddenJsonType;
}
public void setOverRiddenJsonType(Object overRiddenJsonType) {
this.overRiddenJsonType = overRiddenJsonType;
}
}
public class FooConsumer {
public void consumeFoo(Foo foo) {
Boolean b = false;
Bar bar = null;
if (foo.getOverRiddenJsonType() instanceof Boolean) {
b = (Boolean)foo.getOverRiddenJsonType();
// Worry about an NPE from unboxing later...
} else if (foo.getOverRiddenJsonType() instanceof Bar) {
bar = (Bar)foo.getOverRiddenJsonType();
}
// ...
}
}
If, on the other hand, you do control the API, then a better solution would be to restructure your JSON such that success is always boolean, and the rest of the data is either a top-level field or a member of results:
{
"succeeded": true,
"version": 1.0,
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
...
}
]
}

I would suggest to generate a plain POJO for the JSON content below using the tool JSONschema2POJO.
While generating the POJO you can select Source type as JSON and Annotation style as none.
{
"succeeded": {
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
"fieldB": "2016-05-25T22:43:52Z",
"fieldC": "iws-user-cfg-proxy-beta",
"updated_at": "2016-05-25T22:43:52Z"
}
},
{
"get_info": {
"fieldA": "4551542",
"fieldB": "2016-07-27T22:26:27Z",
"fieldC": "silkRoot",
"updated_at": "2016-07-27T22:26:27Z"
}
}
]
}
}
Once you added the generated bean into your project, you could add this overloaded method in your mapper class:
private Succeeded succeeded;
/**
*
* #return
* The succeeded
*/
public Succeeded getSucceeded() {
return succeeded;
}
/**
*
* #param succeeded
* The succeeded
*/
public void setSucceeded(Succeeded succeeded) {
this.succeeded = succeeded;
}

Related

How to fix API authentication problem in Kotlin Android app?

I developed an API in Laravel for reading some data with authentication. Now in my app I need to send the token in my header for API to respond. Every time i login with app, I'm getting token without problem, but i can't provide token in header and it's returning a null token response. Now every time i reopen my app everything is fine but problem appear only when i login.
Please read my code and say if you found the bug.
This is my (AppServer.kt). I use this for adding the token to my header
class AppServer private constructor(private val client: INetworkClient) : IAppServer {
private val gson = Gson()
companion object {
private var instance: AppServer? = null
fun getInstance(): AppServer {
val token = AppLoggedInUser.getInstance()?.userProfile?.userToken ?: ""
if (instance == null)
instance = AppServer(
MixedNetworkClient(
mHeaders = mutableMapOf(
Headers.CONTENT_TYPE to "application/json",
"X-Requested-With" to "XMLHttpRequest",
"Authorization" to "Bearer $token"
),
mBasePath = "https://myWebsiteURL.com/"
)
)
return instance!!
}
}
override fun getPurchasedItems(): Observable<Pair<ResponseState, List<OrderInfo>?>> {
return Observable.create<Pair<ResponseState, List<OrderInfo>?>> { emitter ->
val (items, statusCode, msg, error) =
client.get(
"api/users/${AppLoggedInUser.getInstance().userProfile.userId}/orders",
{ responseStr ->
try {
val orders = mutableListOf<OrderInfo>()
val jArray = JSONArray(responseStr)
for (i in 0 until jArray.length()) {
val jObject = jArray.getJSONObject(i)
val order =
gson.fromJson<OrderInfo>(jObject.toString(), OrderInfo::class.java)
if (order.isPaymentSuccessful)
orders.add(order)
}
if (orders.isEmpty())
emitter.onNext(pair(empty(), null))
else
emitter.onNext(pair(success(), orders))
} catch (t: Throwable) {
Timber.e(t)
emitter.onNext(pair(ResponseState.internalError(t), null))
}
})
}.attachSchedulers()
}
override fun getDiscountDetailsById(id: Int): Observable<Pair<ResponseState, DiscountDetails?>> {
return Observable.create<Pair<ResponseState, DiscountDetails?>> { emitter ->
try {
client.post("api/post", listOf("post_id" to id.toString())) { responseStr ->
val jObject = JSONObject(responseStr)
var discount: DiscountDetails? = null
if (jObject.has("ID"))
discount =
gson.fromJson<DiscountDetails>(jObject.toString(), DiscountDetails::class.java)
if (discount != null)
emitter.onNext(pair(success(), discount))
else
emitter.onNext(pair(notFound404(), null))
}
} catch (t: Throwable) {
Timber.e(t)
emitter.onNext(pair(ResponseState.internalError(t), null))
}
}.attachSchedulers()
}
}
and this is my (AppLoggedInUser.java) I use it for getting my current user token.
package com.fartaak.gilantakhfif.utilities;
import android.content.Context;
import com.fartaak.gilantakhfif.backend.server.ParsingGSON;
import com.fartaak.gilantakhfif.model.UserProfile;
public class AppLoggedInUser extends AppPreferences {
public static final String NAM_LOGIN_SdPs = "login";
public static final String KEY_USER_TOKEN = "tokenPor";
private static AppLoggedInUser mInstance;
private final String KEY_LOGIN = "prefP";
private boolean isCompletelyRegistered;
public static void init(Context context) {
if (mInstance == null) {
mInstance = new AppLoggedInUser(context);
}
}
public static AppLoggedInUser getInstance() {
if (mInstance != null) {
return mInstance;
} else {
throw new IllegalStateException(
"you should call init to initialize only once per app launch before calling getInstance");
}
}
private AppLoggedInUser(Context context) {
super(NAM_LOGIN_SdPs, context);
}
public String getUserToken() {
return getField(KEY_USER_TOKEN);
}
public void clearUserProfile() {
removeField(KEY_LOGIN);
}
public UserProfile getUserProfile() {
String data = getField(KEY_LOGIN);
if (data == null) {
return null;
}
//return new Gson().fromJson(data, UserProfile.class);
return ParsingGSON.getInstance().getParsingJSONObject(data, UserProfile.class, null);
}
public boolean isRegisterCompleted() {
if (!isCompletelyRegistered) {
UserProfile userProfile = getUserProfile();
if (userProfile.getUserName() == null) {
return false;
} else {
isCompletelyRegistered = true;
}
}
return true;
}
public boolean isUserProfile() {
return isField(KEY_LOGIN);
}
public void setUserProfile(UserProfile userProfile) {
String json = ParsingGSON.getInstance().toJSONObject(userProfile, UserProfile.class, null);
setField(KEY_LOGIN, json);
}
}
I think the problem is with my second class.

Read JSON Nested element using reflection without using JsonFactory or ObjectMapper

[Unable to access property of another object stored in Arraylist]
I am creating an function to get JSON input in object from RESTful Web service input and format it again in JSON format to call other web service.
I have limitation that I can not use any JSON API for object mapping hence using Java reflection core API.
I am able to create JSON format from Input for simple elements but unable to access nested elements (another user defined POJO class ). I am using arraylist.
Input
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": [
{
"itemType": "NODE-ID",
"ItemName": "22BT_ORNC03"
},
{
"ItemType": "CCT",
"ItemName": "A_circuit_id"
}]
}
}
GenesisIncidents.class
import java.util.ArrayList;
import java.util.Date;
public class GenesisIncidents {
private String service;
private String affectedCI;
private ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems;
public GenesisIncidents(){}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getAffectedCI() {
return affectedCI;
}
public void setAffectedCI(String affectedCI) {
this.affectedCI = affectedCI;
}
public ArrayList<AdditionalAffectedItems> getOpt_additionalAffectedItems() {
return opt_additionalAffectedItems;
}
public void setOpt_additionalAffectedItems(ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems) {
this.opt_additionalAffectedItems = opt_additionalAffectedItems;
}
}
AdditionalAffectedItems.class
public class AdditionalAffectedItems {
private String itemType;
private String itemName;
public AdditionalAffectedItems(){
super();
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
Implemetation
public void updateTicketExt(GenesisIncidents genesisIncidents) {
try{
Field allFields[]=genesisIncidents.getClass().getDeclaredFields();
Method allMethods[] = genesisIncidents.getClass().getDeclaredMethods();
String jsonString ="{\r\n \""+genesisIncidents.getClass().getName().toString().substring(48)+"\": {";
final String preStr="\r\n \""; //To create a JSON object format.
final String postStr="\": "; //To create a JSON object format.
int totalNoOfFields=allFields.length;
for (Field field : allFields) {
System.out.println(field.getType());
String getter="get"+StringUtils.capitalize(field.getName());
Method method= genesisIncidents.getClass().getMethod(getter, null);
try{
if(field.getType().toString().contains("Integer"))
jsonString=jsonString + preStr + field.getName() + postStr +method.invoke(genesisIncidents).toString()+",";
else
jsonString=jsonString + preStr + field.getName() + postStr +"\""+method.invoke(genesisIncidents).toString()+"\",";
if(field.getType().toString().contains("ArrayList")){
System.out.println("ArrayListElement found");
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
//convertArrayToJSON(field, genesisIncidents);
}
}catch(NullPointerException npe)
{
System.out.println("Null value in field.");
continue;
}
}
jsonString=jsonString.substring(0,jsonString.length()-1);
jsonString=jsonString+"\r\n }\r\n }";
System.out.println("\n"+jsonString);
}catch(Exception jex){
jex.printStackTrace();
}
}
My below code line is unable to access object stored under array list.
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
OUTPUT
karaf#root>class java.lang.String
class java.lang.String
class java.lang.String
class java.util.ArrayList
ArrayListElement found
null
null
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": " [org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#5881a 895, org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#399b4e eb]"
}
}
I have fiddled around with your example I have managed to get it working. This will produce the correct JSON string by passing in an instance of a GenesisIncident object. I guess that there is much room for improvement here but this can serve as an example.
public static String genesisToJson(GenesisIncidents incidents) {
try{
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{\r\n \"")
.append(incidents.getClass().getSimpleName())
.append("\": {");
Field allFields[] = incidents.getClass().getDeclaredFields();
for (Field field : allFields) {
String getter = getGetterMethod(field);
Method method = incidents.getClass().getMethod(getter, null);
try{
if(field.getType().isAssignableFrom(Integer.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr)
.append(method.invoke(incidents).toString()).append(",");
} else if (field.getType().isAssignableFrom(String.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr).append("\"")
.append(method.invoke(incidents).toString()).append("\",");
} else if (field.getType().isAssignableFrom(List.class)) {
System.out.println("ArrayListElement found");
getInnerObjectToJson(field, incidents.getOptItems(), jsonBuilder);
}
} catch(NullPointerException npe) {
System.out.println("Null value in field.");
continue;
}
}
jsonBuilder.append("\r\n } \r\n }");
return jsonBuilder.toString();
}catch(Exception jex){
jex.printStackTrace();
}
return null;
}
private static void getInnerObjectToJson(Field field, List<AdditionalAffectedItems> items, StringBuilder builder)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
builder.append(preStr).append(field.getName()).append(postStr).append("[");
for (var item : items) {
var fields = List.of(item.getClass().getDeclaredFields());
builder.append("{");
for (var f : fields) {
String getter = getGetterMethod(f);
Method method = item.getClass().getMethod(getter, null);
builder.append(preStr).append(f.getName()).append(postStr).append("\"")
.append(method.invoke(item).toString()).append("\"");
if (!(fields.indexOf(f) == (fields.size() - 1))) {
builder.append(",");
}
}
if (items.indexOf(item) == (items.size() - 1)) {
builder.append("}\r\n");
} else {
builder.append("},\r\n");
}
}
builder.append("]");
}
private static String getGetterMethod(Field field) {
return "get" + StringUtils.capitalize(field.getName());
}

Hibernate gives a strange ClassCast exception (using Transformers)

This code:
#Override
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() {
String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS;
Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery);
List<FactCodeDto> factDtoList = query.list(); //line 133
return factDtoList;
}
calling this method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
gives me a ClassCastException -> part of the trace:
Caused by: java.lang.ClassCastException: org.bamboomy.cjr.dto.FactCodeDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125)
at org.bamboomy.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133)
Which is pretty strange because, indeed, if you look up the source code of Hibernate it tries to do this:
#Override
#SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value ); //line 102
}
Which doesn't make any sense...
target is of type Class and this code tries to cast it to Map,
why does it try to do that???
any pointers are more than welcome...
I'm using Hibernate 5 (and am upgrading from 3)...
edit: I also use Spring (4.2.1.RELEASE; also upgrading) which calls these methods upon deploy, any debugging pointers are most welcome as well...
edit 2: (the whole FactCodeDto class, as requested)
package org.bamboomy.cjr.dto;
import org.bamboomy.cjr.model.FactCode;
import org.bamboomy.cjr.model.FactCodeType;
import org.bamboomy.cjr.utility.FullDateUtil;
import org.bamboomy.cjr.utility.Locales;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.util.Assert;
import java.util.*;
#Getter
#Setter
#ToString
public class FactCodeDto extends TreeNodeValue {
private String cdFact;
private String cdFactSuffix;
private Boolean isSupplementCode;
private Boolean isTitleCode;
private Boolean mustBeFollowed;
private Date activeFrom;
private Date activeTo;
private Boolean isCode;
private Long idFact;
private Long idParent;
private String type;
Map<Locale, String> description = new HashMap<Locale, String>(3);
public FactCodeDto() {
}
public FactCodeDto(String prefix, String suffix) {
super();
this.cdFact = prefix;
this.cdFactSuffix = suffix;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
this.idFact = idFact;
this.idParent = idParent;
this.isCode = isCode;
this.isTitleCode = isTitleCode;
this.activeFrom = from;
this.activeTo = to;
if (descriptions != null) {
this.description = descriptions;
}
this.type = type;
}
public FactCodeDto(FactCode fc) {
this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode());
}
public String formatCode() {
return FactCode.formatCode(cdFact, cdFactSuffix);
}
public boolean isActive() {
Date now = new Date(System.currentTimeMillis());
return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo);
}
public void setDescFr(String s) {
description.put(Locales.FRENCH, s);
}
public void setDescNl(String s) {
description.put(Locales.DUTCH, s);
}
public void setDescDe(String s) {
description.put(Locales.GERMAN, s);
}
/**
* public String toString() {
* StringBuilder sb = new StringBuilder();
* sb.append(getIdFact() + ": ")
* .append(getIdParent() + ": ")
* .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal "))
* .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed "));
* return sb.toString();
* }
*/
public Map<Locale, String> getDescription() {
return description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
String fullCode = formatCode();
result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FactCodeDto other = (FactCodeDto) obj;
return formatCode().equals(other.formatCode());
}
#Override
public boolean isChildOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isChild = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact());
}
}
return isChild;
}
#Override
public boolean isBrotherOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isBrother = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent());
}
}
return isBrother;
}
#Override
public boolean isParentOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isParent = false;
if (value instanceof FactCodeDto) {
isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent());
}
return isParent;
}
#Override
public int compareTo(TreeNodeValue to) {
if (to instanceof FactCodeDto) {
return formatCode().compareTo(((FactCodeDto) to).formatCode());
} else return 1;
}
public String getCode() {
return formatCode();
}
}
I found that AliasToBean has changed in Hibernate 5. For me adding getter for my field fixed the problem.
This exception occurs when the setters and getters are not mapped correctly to the column names.
Make sure you have the correct getters and setters for the query(Correct names and correct datatypes).
Read more about it here:
http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/
I do some investigation on this question. The problem is that Hibernate converts aliases for column names to upper case — cdFact becomesCDFACT.
Read for a more deeply explanation and workaround here:
mapping Hibernate query results to custom class?
In the end it wasn't so hard to find a solution,
I just created my own (custom) ResultTransformer and specified that in the setResultTransformer method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer());
//return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
the code of the custom result transformer:
package org.bamboomy.cjr.dao.factcode;
import org.bamboomy.cjr.dto.FactCodeDto;
import java.util.Date;
import java.util.List;
/**
* Created by a162299 on 3-11-2015.
*/
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
FactCodeDto result = new FactCodeDto();
for (int i = 0; i < objects.length; i++) {
setField(result, strings[i], objects[i]);
}
return result;
}
private void setField(FactCodeDto result, String string, Object object) {
if (string.equalsIgnoreCase("cdFact")) {
result.setCdFact((String) object);
} else if (string.equalsIgnoreCase("cdFactSuffix")) {
result.setCdFactSuffix((String) object);
} else if (string.equalsIgnoreCase("isSupplementCode")) {
result.setIsSupplementCode((Boolean) object);
} else if (string.equalsIgnoreCase("isTitleCode")) {
result.setIsTitleCode((Boolean) object);
} else if (string.equalsIgnoreCase("mustBeFollowed")) {
result.setMustBeFollowed((Boolean) object);
} else if (string.equalsIgnoreCase("activeFrom")) {
result.setActiveFrom((Date) object);
} else if (string.equalsIgnoreCase("activeTo")) {
result.setActiveTo((Date) object);
} else if (string.equalsIgnoreCase("descFr")) {
result.setDescFr((String) object);
} else if (string.equalsIgnoreCase("descNl")) {
result.setDescNl((String) object);
} else if (string.equalsIgnoreCase("descDe")) {
result.setDescDe((String) object);
} else if (string.equalsIgnoreCase("type")) {
result.setType((String) object);
} else if (string.equalsIgnoreCase("idFact")) {
result.setIdFact((Long) object);
} else if (string.equalsIgnoreCase("idParent")) {
result.setIdParent((Long) object);
} else if (string.equalsIgnoreCase("isCode")) {
result.setIsCode((Boolean) object);
} else {
throw new RuntimeException("unknown field");
}
}
#Override
public List transformList(List list) {
return list;
}
}
in hibernate 3 you could set Aliasses to queries but you can't do that anymore in hibernate 5 (correct me if I'm wrong) hence the aliasToBean is something you only can use when actually using aliasses; which I didn't, hence the exception.
Im my case :
=> write sql query and try to map result to Class List
=> Use "Transformers.aliasToBean"
=> get Error "cannot be cast to java.util.Map"
Solution :
=> just put \" before and after query aliases
ex:
"select first_name as \"firstName\" from test"
The problem is that Hibernate converts aliases for column names to upper case or lower case
I solved it by defining my own custom transformer as given below -
import org.hibernate.transform.BasicTransformerAdapter;
public class FluentHibernateResultTransformer extends BasicTransformerAdapter {
private static final long serialVersionUID = 6825154815776629666L;
private final Class<?> resultClass;
private NestedSetter[] setters;
public FluentHibernateResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
createCachedSetters(resultClass, aliases);
Object result = ClassUtils.newInstance(resultClass);
for (int i = 0; i < aliases.length; i++) {
setters[i].set(result, tuple[i]);
}
return result;
}
private void createCachedSetters(Class<?> resultClass, String[] aliases) {
if (setters == null) {
setters = createSetters(resultClass, aliases);
}
}
private static NestedSetter[] createSetters(Class<?> resultClass, String[] aliases) {
NestedSetter[] result = new NestedSetter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
result[i] = NestedSetter.create(resultClass, aliases[i]);
}
return result;
}
}
And used this way inside the repository method -
#Override
public List<WalletVO> getWalletRelatedData(WalletRequest walletRequest,
Set<String> requiredVariablesSet) throws GenericBusinessException {
String query = getWalletQuery(requiredVariablesSet);
try {
if (query != null && !query.isEmpty()) {
SQLQuery sqlQuery = mEntityManager.unwrap(Session.class).createSQLQuery(query);
return sqlQuery.setResultTransformer(new FluentHibernateResultTransformer(WalletVO.class))
.list();
}
} catch (Exception ex) {
exceptionThrower.throwDatabaseException(null, false);
}
return Collections.emptyList();
}
It worked perfectly !!!
Try putting Column names and field names both in capital letters.
This exception occurs when the class that you specified in the AliasToBeanResultTransformer does not have getter for the corresponding columns. Although the exception details from the hibernate are misleading.

Json array and retrofit

I've this kind of json response:
{
error: false
stats: {
punti: 150
punti2: 200
}-
}
I created a StatsReceiver class:
public class StatsReceiver {
Boolean error;
Stats stat;
public Boolean isError() {
if (error == null)
return true;
else
return error;
}
public int getPunti() {
if (stat == null)
return -1;
else
return stat.getPunti();
}
private class Stats {
private int punti = 0;
public int getPunti() {
return punti;
}
public void setPunti(int punti) {
this.punti = punti;
}
public int getPunti2() {
return punti2;
}
public void setPunti2(int punti2) {
this.punti2 = punti2;
}
private int punti2 = 0;
public Stats(int punti, int punti2) {
this.punti = punti;
this.punti2 = punti2;
}
}
}
Next:
#GET("/v1/stats")
void stats(#Header("Auth") String code,
Callback<StatsReceiver> object);
Now when I do:
apiServiceUsers.stats(apiKey, new Callback<StatsReceiver>() {
#Override
public void success(StatsReceiver statsReceiver, Response response) {
if (statsReceiver.isError()) {
Toast.makeText(this, "Error", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, statsReceiver.getPunti(), Toast.LENGTH_LONG).show();
}
}
Error is false as expected, but getPunti() return always -1, so stat object is always null.
What's wrong?
P.S in the Log console, there is:
{"error":false,"stats":{"punti":150,"punti2":200}}
In your JSON example the key is stats; but in your Java class the member variable is called stat. For Gson to work, these must be either exactly the same, or you must use #SerializedName to tell Gson which JSON key corresponds to which variable:
#SerializedName("stats")
Stats statOrSomethingElseEntirely;

Get single field from JSON using Jackson

Given an arbitrary JSON I would like to get value of a single field contentType. How to do it with Jackson?
{
contentType: "foo",
fooField1: ...
}
{
contentType: "bar",
barArray: [...]
}
Related
How to find specified name and its value in JSON-string from Java? (GSON)
Using gson to deserialize specific JSON field of an object (GSON)
The Jackson Way
Considering that you don't have a POJO describing your data structure, you could simply do:
final String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
final ObjectNode node = new ObjectMapper().readValue(json, ObjectNode.class);
// ^
// actually, try and *reuse* a single instance of ObjectMapper
if (node.has("contentType")) {
System.out.println("contentType: " + node.get("contentType"));
}
Addressing concerns in the comments section
If, however, you wish to not consume the entire source String, but simply access a specific property whose path you know, you'll have to write it yourself, leveraging a Tokeniser.
Actually, it's the weekend and I got time on my hands, so I could give you a head start: here's a basic one! It can run in strict mode and spew out sensible error messages, or be lenient and return Optional.empty when the request couldn't be fulfilled.
public static class JSONPath {
protected static final JsonFactory JSON_FACTORY = new JsonFactory();
private final List<JSONKey> keys;
public JSONPath(final String from) {
this.keys = Arrays.stream((from.startsWith("[") ? from : String.valueOf("." + from))
.split("(?=\\[|\\]|\\.)"))
.filter(x -> !"]".equals(x))
.map(JSONKey::new)
.collect(Collectors.toList());
}
public Optional<String> getWithin(final String json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final String json, final boolean strict) throws IOException {
try (final InputStream stream = new StringInputStream(json)) {
return this.getWithin(stream, strict);
}
}
public Optional<String> getWithin(final InputStream json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final InputStream json, final boolean strict) throws IOException {
return getValueAt(JSON_FACTORY.createParser(json), 0, strict);
}
protected Optional<String> getValueAt(final JsonParser parser, final int idx, final boolean strict) throws IOException {
try {
if (parser.isClosed()) {
return Optional.empty();
}
if (idx >= this.keys.size()) {
parser.nextToken();
if (null == parser.getValueAsString()) {
throw new JSONPathException("The selected node is not a leaf");
}
return Optional.of(parser.getValueAsString());
}
this.keys.get(idx).advanceCursor(parser);
return getValueAt(parser, idx + 1, strict);
} catch (final JSONPathException e) {
if (strict) {
throw (null == e.getCause() ? new JSONPathException(e.getMessage() + String.format(", at path: '%s'", this.toString(idx)), e) : e);
}
return Optional.empty();
}
}
#Override
public String toString() {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.stream().map(JSONKey::toString).collect(Collectors.joining()));
}
private String toString(final int idx) {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.subList(0, idx).stream().map(JSONKey::toString).collect(Collectors.joining()));
}
#SuppressWarnings("serial")
public static class JSONPathException extends RuntimeException {
public JSONPathException() {
super();
}
public JSONPathException(final String message) {
super(message);
}
public JSONPathException(final String message, final Throwable cause) {
super(message, cause);
}
public JSONPathException(final Throwable cause) {
super(cause);
}
}
private static class JSONKey {
private final String key;
private final JsonToken startToken;
public JSONKey(final String str) {
this(str.substring(1), str.startsWith("[") ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);
}
private JSONKey(final String key, final JsonToken startToken) {
this.key = key;
this.startToken = startToken;
}
/**
* Advances the cursor until finding the current {#link JSONKey}, or
* having consumed the entirety of the current JSON Object or Array.
*/
public void advanceCursor(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (!this.startToken.equals(token)) {
throw new JSONPathException(String.format("Expected token of type '%s', got: '%s'", this.startToken, token));
}
if (JsonToken.START_ARRAY.equals(this.startToken)) {
// Moving cursor within a JSON Array
for (int i = 0; i != Integer.valueOf(this.key).intValue(); i++) {
JSONKey.skipToNext(parser);
}
} else {
// Moving cursor in a JSON Object
String name;
for (parser.nextToken(), name = parser.getCurrentName(); !this.key.equals(name); parser.nextToken(), name = parser.getCurrentName()) {
JSONKey.skipToNext(parser);
}
}
}
/**
* Advances the cursor to the next entry in the current JSON Object
* or Array.
*/
private static void skipToNext(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, 1);
} else if (JsonToken.END_ARRAY.equals(token) || JsonToken.END_OBJECT.equals(token)) {
throw new JSONPathException("Could not find requested key");
}
}
/**
* Recursively consumes whatever is next until getting back to the
* same depth level.
*/
private static void skipToNextImpl(final JsonParser parser, final int depth) throws IOException {
if (depth == 0) {
return;
}
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, depth + 1);
} else {
skipToNextImpl(parser, depth - 1);
}
}
#Override
public String toString() {
return String.format(this.startToken.equals(JsonToken.START_ARRAY) ? "[%s]" : ".%s", this.key);
}
}
}
Assuming the following JSON content:
{
"people": [{
"name": "Eric",
"age": 28
}, {
"name": "Karin",
"age": 26
}],
"company": {
"name": "Elm Farm",
"address": "3756 Preston Street Wichita, KS 67213",
"phone": "857-778-1265"
}
}
... you could use my JSONPath class as follows:
final String json = "{\"people\":[],\"company\":{}}"; // refer to JSON above
System.out.println(new JSONPath("people[0].name").getWithin(json)); // Optional[Eric]
System.out.println(new JSONPath("people[1].name").getWithin(json)); // Optional[Karin]
System.out.println(new JSONPath("people[2].name").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("people[0].age").getWithin(json)); // Optional[28]
System.out.println(new JSONPath("company").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("company.name").getWithin(json)); // Optional[Elm Farm]
Keep in mind that it's basic. It doesn't coerce data types (every value it returns is a String) and only returns leaf nodes.
Actual test case
It handles InputStreams, so you can test it against some giant JSON document and see that it's much faster than it would take your browser to download and display its contents:
System.out.println(new JSONPath("info.contact.email")
.getWithin(new URL("http://test-api.rescuegroups.org/v5/public/swagger.php").openStream()));
// Optional[support#rescuegroups.org]
Quick test
Note I'm not re-using any already existing JSONPath or ObjectMapper so the results are inaccurate -- this is just a very rough comparison anyways:
public static Long time(final Callable<?> r) throws Exception {
final long start = System.currentTimeMillis();
r.call();
return Long.valueOf(System.currentTimeMillis() - start);
}
public static void main(final String[] args) throws Exception {
final URL url = new URL("http://test-api.rescuegroups.org/v5/public/swagger.php");
System.out.println(String.format( "%dms to get 'info.contact.email' with JSONPath",
time(() -> new JSONPath("info.contact.email").getWithin(url.openStream()))));
System.out.println(String.format( "%dms to just download the entire document otherwise",
time(() -> new Scanner(url.openStream()).useDelimiter("\\A").next())));
System.out.println(String.format( "%dms to bluntly map it entirely with Jackson and access a specific field",
time(() -> new ObjectMapper()
.readValue(url.openStream(), ObjectNode.class)
.get("info").get("contact").get("email"))));
}
378ms to get 'info.contact.email' with JSONPath
756ms to just download the entire document otherwise
896ms to bluntly map it entirely with Jackson and access a specific field
Just want to update for 2019. I found the following easiest to impl:
//json can be file or String
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.path("contentType").asText();
I would suggest to use path instead of get as get throws a NPE, where path returns with a default 0 or "", which is safer to work with if setting up the parsing correctly for 1st time.
My $0.02
If you are using JSON jars in your application then the following code snippet is useful:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JSONObject jsonObject = new JSONObject(json);
System.out.println(jsonObject.getString("contentType"));
and if you are using Gson jars then the same code will look like following:
Gson gson = new GsonBuilder().create();
Map jsonMap = gson.fromJson(json, Map.class);
System.out.println(jsonMap.get("contentType"));
Another way is:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.get("contentType").asText();
I faced this issue when I decided to use Jackson as the json library for a project I worked on; mainly for its speed. I was already used to using org.json and Gson for my projects.
I quickly found out though that many tasks that were trivial in org.json and Gson were not so straightforward in Jackson
So I wrote the following classes to make things easier for me.
The classes below will allow you to use Jackson as easily as you would the simple org.json library, while still retaining the power and speed of Jackson
I wrote the whole thing in a few hours, so feel free to debug and suit the code to your own purposes.
Note that JSONObject/JSONArray below will do exactly what the OP wants.
The first is JSONObject which has similar methods to org.json.JSONObject; but at heart runs Jackson code to build JSON and parse json strings.
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONObject {
ObjectNode parseNode;
public JSONObject() {
this.parseNode = JsonNodeFactory.instance.objectNode(); // initializing
}
public JSONObject(String json) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
try {
this.parseNode = mapper.readValue(json, ObjectNode.class);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void put(String key, String value) {
parseNode.put("key", value); // building
}
public void put(String key, boolean value) {
parseNode.put("key", value); // building
}
public void put(String key, int value) {
parseNode.put("key", value); // building
}
public void put(String key, short value) {
parseNode.put("key", value); // building
}
public void put(String key, float value) {
parseNode.put("key", value); // building
}
public void put(String key, long value) {
parseNode.put("key", value); // building
}
public void put(String key, double value) {
parseNode.put("key", value); // building
}
public void put(String key, byte[] value) {
parseNode.put("key", value); // building
}
public void put(String key, BigInteger value) {
parseNode.put("key", value); // building
}
public void put(String key, BigDecimal value) {
parseNode.put("key", value); // building
}
public void put(String key, Object[] value) {
ArrayNode anode = parseNode.putArray(key);
for (Object o : value) {
anode.addPOJO(o); // building
}
}
public void put(String key, JSONObject value) {
parseNode.set(key, value.parseNode);
}
public void put(String key, Object value) {
parseNode.putPOJO(key, value);
}
public static class Parser<T> {
public T decode(String json, Class clazz) {
try {
return new Converter<T>().fromJsonString(json, clazz);
} catch (IOException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public int optInt(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ObjectNode nod = parseNode.with(key);
JSONObject obj = new JSONObject();
obj.parseNode = nod;
return obj;
}
}
return new JSONObject();
}
public JSONArray optJSONArray(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ArrayNode nod = parseNode.withArray(key);
JSONArray obj = new JSONArray();
if (nod != null) {
obj.parseNode = nod;
return obj;
}
}
}
return new JSONArray();
}
public String optString(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return parseNode != null && nod.isTextual() ? nod.asText("") : "";
}
return "";
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Here is the code for the JSONArray equivalent that works like org.json.JSONArray; but uses Jackson code.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONArray {
protected ArrayNode parseNode;
public JSONArray() {
this.parseNode = JsonNodeFactory.instance.arrayNode(); // initializing
}
public JSONArray(String json) throws JsonProcessingException{
ObjectMapper mapper = new ObjectMapper();
this.parseNode = mapper.readValue(json, ArrayNode.class);
}
public void putByte(byte val) {
parseNode.add(val);
}
public void putShort(short val) {
parseNode.add(val);
}
public void put(int val) {
parseNode.add(val);
}
public void put(long val) {
parseNode.add(val);
}
public void pu(float val) {
parseNode.add(val);
}
public void put(double val) {
parseNode.add(val);
}
public void put(String val) {
parseNode.add(val);
}
public void put(byte[] val) {
parseNode.add(val);
}
public void put(BigDecimal val) {
parseNode.add(val);
}
public void put(BigInteger val) {
parseNode.add(val);
}
public void put(Object val) {
parseNode.addPOJO(val);
}
public void put(int index, JSONArray value) {
parseNode.set(index, value.parseNode);
}
public void put(int index, JSONObject value) {
parseNode.set(index, value.parseNode);
}
public String optString(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asText("") : "";
}
return "";
}
public int optInt(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isObject()){
ObjectNode obn = (ObjectNode) nod;
JSONObject obj = new JSONObject();
obj.parseNode = obn;
return obj;
}
}
}
return new JSONObject();
}
public JSONArray optJSONArray(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isArray()){
ArrayNode anode = (ArrayNode) nod;
JSONArray obj = new JSONArray();
obj.parseNode = anode;
return obj;
}
}
}
return new JSONArray();
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Finally for a one size-fits-all-most-likely for encoding and decoding your Java classes to JSON, I added this simple class:
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class Converter<T> {
// Serialize/deserialize helpers
private Class clazz;
public Converter() {}
public T fromJsonString(String json , Class clazz) throws IOException {
this.clazz = clazz;
return getObjectReader().readValue(json);
}
public String toJsonString(T obj) throws JsonProcessingException {
this.clazz = obj.getClass();
return getObjectWriter().writeValueAsString(obj);
}
private ObjectReader requestReader;
private ObjectWriter requestWriter;
private void instantiateMapper() {
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
requestReader = mapper.readerFor(clazz);
requestWriter = mapper.writerFor(clazz);
}
private ObjectReader getObjectReader() {
if (requestReader == null) {
instantiateMapper();
}
return requestReader;
}
private ObjectWriter getObjectWriter() {
if (requestWriter == null) {
instantiateMapper();
}
return requestWriter;
}
}
Now to taste(test) the sauce(code), use the following methods:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class SimplerJacksonTest {
static class Credentials {
private String userName;
private String uid;
private String password;
private long createdAt;
public Credentials() {
}
public Credentials(String userName, String uid, String password, long createdAt) {
this.userName = userName;
this.uid = uid;
this.password = password;
this.createdAt = createdAt;
}
#JsonProperty("userName")
public String getUserName() {
return userName;
}
#JsonProperty("userName")
public void setUserName(String userName) {
this.userName = userName;
}
#JsonProperty("uid")
public String getUid() {
return uid;
}
#JsonProperty("uid")
public void setUid(String uid) {
this.uid = uid;
}
#JsonProperty("password")
public String getPassword() {
return password;
}
#JsonProperty("password")
public void setPassword(String password) {
this.password = password;
}
#JsonProperty("createdAt")
public long getCreatedAt() {
return createdAt;
}
#JsonProperty("createdAt")
public void setCreatedAt(long createdAt) {
this.createdAt = createdAt;
}
public String encode() {
try {
return new Converter<Credentials>().toJsonString(this);
} catch (JsonProcessingException ex) {
Logger.getLogger(Credentials.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public Credentials decode(String jsonData) {
try {
return new Converter<Credentials>().fromJsonString(jsonData, Credentials.class);
} catch (Exception ex) {
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public static JSONObject testJSONObjectBuild() {
JSONObject obj = new JSONObject();
Credentials cred = new Credentials("Adesina", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String arr[] = new String[]{"Boy", "Girl", "Man", "Woman"};
int nums[] = new int[]{0, 1, 2, 3, 4, 5};
obj.put("creds", cred);
obj.put("pronouns", arr);
obj.put("creds", cred);
obj.put("nums", nums);
System.out.println("json-coding: " + obj.toCuteString());
return obj;
}
public static void testJSONObjectParse(String json) {
JSONObject obj;
try {
obj = new JSONObject(json);
JSONObject credsObj = obj.optJSONObject("creds");
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
System.out.println("<<---Parse Results--->>");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static JSONArray testJSONArrayBuild() {
JSONArray array = new JSONArray();
array.put(new Credentials("Lawani", "001uadywdbs", "ampouehehu", System.currentTimeMillis()));
array.put("12");
array.put(98);
array.put(Math.PI);
array.put("Good scores!");
System.out.println("See the built array: "+array.toCuteString());
return array;
}
public static void testJSONArrayParse(String json) {
try {
JSONArray array = new JSONArray(json);
JSONObject credsObj = array.optJSONObject(0);
//Parse credentials in index 0
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
//Now return to the main array and parse other entries
String twelve = array.optString(1);
int ninety = array.optInt(2);
double pi = array.optDouble(3);
String scoreNews = array.optString(4);
System.out.println("Parse Results");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
System.out.println("Parse Results");
System.out.println("index 1 = " + twelve);
System.out.println("index 2 = " + ninety);
System.out.println("index 3 = " + pi);
System.out.println("index 4 = " + scoreNews);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String testCredentialsEncode(){
Credentials cred = new Credentials("Olaoluwa", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String encoded = cred.encode();
System.out.println("encoded credentials = "+encoded);
return encoded;
}
public static Credentials testCredentialsDecode(String json){
Credentials cred = new Credentials().decode(json);
System.out.println("encoded credentials = "+cred.encode());
return cred;
}
public static void main(String[] args) {
JSONObject jo = testJSONObjectBuild();
testJSONObjectParse(jo.toString());
JSONArray ja = testJSONArrayBuild();
testJSONArrayParse(ja.toString());
String credsJSON = testCredentialsEncode();
testCredentialsDecode(credsJSON);
}
}
To get the source code in a place, instead of having to copy the one here, see:
the code on Github

Categories