Json array and retrofit - java

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;

Related

GET request from rest api in android studio : Expected BEGIN_ARRAY but was STRING

I am new to android app development with java and I am trying to fetch data from an external api .
However I get the error : Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $.The API returns a result in the form of :
[ {} ,{} , ... ]
where I have defined every object as a single result and in my API interface I want a list of these results .
Each object is in the form of :
{
area: "athens",
areaid: 1002,
dailydose1: 276,
dailydose2: 305,
daydiff: -49,
daytotal: 581,
referencedate: "2021-05-27T00:00:00",
totaldistinctpersons: 25446,
totaldose1: 25446,
totaldose2: 12098,
totalvaccinations: 36960
}
My code :
CovidApi.java
public interface CovidApi {
#GET("/")
Call<List<CovidSingleResult>> getCovidData();
}
CovidSingleResult.java
public class CovidSingleResult {
private int totalvaccinations;
private int daytotal;
private String referencedate;
private int totaldose1;
private int totaldose2;
private String area;
private int areaid;
private int dailydose1;
private int dailydose2;
private int daydiff;
public String getArea() {
return area;
}
public int getDailydose1() {
return dailydose1;
}
public int getDaytotal() {
return daytotal;
}
public int getDailydose2() {
return dailydose2;
}
public String getReferencedate() {
return referencedate;
}
public int getAreaid() {
return areaid;
}
public int getTotaldose1() {
return totaldose1;
}
public int getTotaldose2() {
return totaldose2;
}
public int getDaydiff() {
return daydiff;
}
public int getTotalvaccinations() {
return totalvaccinations;
}
}
Fragment.java where I call the api url
resultText = root.findViewById(R.id.response); //text to set api result
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://data.gov.gr/api/v1/query/mdg_emvolio/date_from="+binding.inputFrom.getText()+"&date_to="+binding.inputTo.getText()+"/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
CovidApi covidApi = retrofit.create(CovidApi.class);
Call<List<CovidSingleResult>> call = covidApi.getCovidData();
call.enqueue(new Callback<List<CovidSingleResult>>() {
#Override
public void onResponse(Call<List<CovidSingleResult>> call, retrofit2.Response<List<CovidSingleResult>> response) {
if(!response.isSuccessful()){
resultText.setText("Code" + response.code());
return;
}else{
List<CovidSingleResult> covidSingleResults = response.body();
for(CovidSingleResult p : covidSingleResults){
String content = "";
content += "total vaccinations :" + p.getTotalvaccinations();
resultText.append(content);
}
}
}
#Override
public void onFailure(Call<List<CovidSingleResult>> call, Throwable t) {
resultText.setText(t.getMessage());
}
});
I would appreciate your help
Error say`s that your response is object and your model in java is list
please replace bellow code in api interface:
Call<CovidSingleResult> getCovidData();

Jackson no suitable constructor found for android.graphics.Bitmap

I'm trying to serialize my Character object with the use of Jackson. The mapper.writeValue method invocation is successful it seems, but when I try to read the value with the use of mapper.readValue I get the following error message:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of android.graphics.Bitmap: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: java.io.FileReader#9ab6557; line: 1, column: 199] (through reference chain: java.lang.Object[][0]->com.myproj.character.Character["compositeClothes"]->com.myproj.character.clothing.CompositeClothing["clothes"]->java.util.ArrayList[0]->com.myproj.character.clothing.concrete.Hat["bitmap"])
These are my classes:
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
#JsonSubTypes({
#JsonSubTypes.Type(value = Hat.class, name = "hat"),
#JsonSubTypes.Type(value = Necklace.class, name = "necklace"),
#JsonSubTypes.Type(value = Shirt.class, name = "shirt")
})
public interface Clothing {
int getCoolness();
int getrId();
Bitmap getBitmap();
}
My hat class:
public class Hat implements Clothing {
private int rId;
private int coolness;
private Bitmap bitmap;
#JsonCreator
public Hat(#JsonProperty("coolness") int coolness, #JsonProperty("bitmap") Bitmap bitmap) {
rId = R.id.hat_image;
this.coolness = coolness;
this.bitmap = bitmap;
}
public int getrId() {
return rId;
}
#Override
public int getCoolness() {
return coolness;
}
public Bitmap getBitmap() {
return bitmap;
}
}
My composite clothing class:
public class CompositeClothing implements Clothing, Iterable<Clothing> {
#JsonProperty("coolness")
private int coolness = 0;
private List<Clothing> clothes = new ArrayList<>();
public void add(Clothing clothing) {
clothes.add(clothing);
}
public void remove(Clothing clothing) {
clothes.remove(clothing);
}
public Clothing getChild(int index) {
if (index >= 0 && index < clothes.size()) {
return clothes.get(index);
} else {
return null;
}
}
#Override
public Iterator<Clothing> iterator() {
return clothes.iterator();
}
#Override
public int getCoolness() {
return coolness;
}
#Override
public int getrId() {
return 0;
}
#Override
public Bitmap getBitmap() {
return null;
}
}
And my character class:
public class Character implements Observable {
private static final transient Character instance = new Character();
#JsonProperty("compositeClothes")
private CompositeClothing clothes = new CompositeClothing();
#JsonProperty("compositeHeadFeatures")
private CompositeHeadFeature headFeatures = new CompositeHeadFeature();
private transient List<Observer> observers = new ArrayList<>();
#JsonProperty("skin")
private Skin skin;
public void attach(Observer observer) {
observers.add(observer);
}
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
public void setSkin(Skin skin) {
this.skin = skin;
notifyAllObservers();
}
public Skin.Color getSkinColor() {
return skin.getColor();
}
public Bitmap getSkinBitmap() {
return skin.getBitmap();
}
public boolean hasSkin() {
return skin != null;
}
public void addClothing(Clothing clothing) {
Clothing oldClothing = (Clothing) getSameTypeObjectAlreadyWorn(clothing);
if (oldClothing != null) {
clothes.remove(oldClothing);
}
clothes.add(clothing);
notifyAllObservers();
}
public CompositeClothing getClothes() {
return clothes;
}
private Object getSameTypeObjectAlreadyWorn(Object newClothing) {
Class<?> newClass = newClothing.getClass();
for (Object clothing : clothes) {
if (clothing.getClass().equals(newClass)) {
return clothing;
}
}
return null;
}
public void removeClothing(Clothing clothing) {
clothes.remove(clothing);
}
public void addHeadFeature(HeadFeature headFeature) {
HeadFeature oldHeadFeature = (HeadFeature) getSameTypeObjectAlreadyWorn(headFeature);
if (oldHeadFeature != null) {
headFeatures.remove(oldHeadFeature);
}
headFeatures.add(headFeature);
notifyAllObservers();
}
public void removeHeadFeature(HeadFeature headFeature) {
headFeatures.remove(headFeature);
}
public CompositeHeadFeature getHeadFeatures() {
return headFeatures;
}
public static Character getInstance() {
return instance;
}
}
The code that I'm using to persist and then read the data:
File charactersFile = new File(getFilesDir() + File.separator + "characters.ser");
ObjectMapper mapper = new ObjectMapper()
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
try (FileWriter fileOut = new FileWriter(charactersFile, false)) {
List<Character> characters = Arrays.asList(character);
mapper.writeValue(fileOut, characters);
} catch (IOException e) {
e.printStackTrace();
}
Character[] characters = null;
try (FileReader fileIn = new FileReader(charactersFile)) {
characters = mapper.readValue(fileIn, Character[].class);
} catch (IOException e) {
e.printStackTrace();
}
Thanks!
If your bitmaps come from assets or resources, there is no point on saving the bitmaps to JSON. That would be a waste of CPU time and disk space. Instead, store a value in the JSON that will allow you to identify the asset or resource to display. However, bear in mind that resource IDs (e.g., R.drawable.foo) can vary between app releases, so that is not a good durable identifier for the image.
I have similar requirement in my app where I need to store drawable data in JSON. I solved it by storing only its string name. For example, if I have resource R.drawable.testBmp then I store it in JSON like :
{
...
"mydrawable" : "testBmp"
}
Then at run time, I will read it and convert is as drawable like following code:
JSONObject jsonObj;
...
String bmpName = jsonObj.getString("mydrawable");
int resId = context.getResources().getIdentifier(bmpName,
"drawable",
context.getPackageName());
Drawable bmp = ContextCompat.getDrawable(context,resId);

Boolean and array data binding using Jackson

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;
}

How to refer to data from within inner class

I'm new to java programming so I apologize for the possibly incorrect wording of the question. I have a boolean function updateEntryDB that should return false if the response from my database is "Error" and true if it is "Success". How do I get the boolean response from the #override method OnSuccessBool, so that my updateEntryDB function will return the proper response? Thanks for any help.
private boolean updateEntryDB(final String tag)
{
//Log.i(TAG, "updateEntryDB");
String np = numPlate.getText().toString();
dbWork dbWork = new dbWork();
dbWork.updateEntryTime(tag, np, requestQueue, new dbWork.VolleyCallback() {
#Override
public void onSuccess(String result) {
}
#Override
public boolean onSuccessBool(String result) {
String dbResponse = result;
test.setText(dbResponse);
String[] errSucc = dbResponse.split(":");
if(errSucc[0].equals("Error"))
{
return false;
}
else if(errSucc[0].equals("Success"))
{
return true;
}
return false;
}
});
}

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.

Categories