I am using official google example code for user subscription play-billing-sample. I get nullpointexception on checking the account hold when switching google accounts (my phone has two google accounts registered as test accounts to test the purchases).
I log into the first account without any problems and purchase basic or premium subscriptions
when I switch to the second account, I get the error below:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference at com.pishimishi.test.classytaxijava.billing.BillingUtilities.isAccountHold(BillingUtilities.java:151)
BillingUtilities.java:
/**
* Returns true if account hold should be shown.
*/
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
!subscription.isEntitlementActive &&
subscription.isAccountHold &&
!subscription.subAlreadyOwned;
}
and SubscriptionStatus.java:
/**
* Local subscription data. This is stored on disk in a database.
*/
#Entity(tableName = "subscriptions")
public class SubscriptionStatus {
public class SubscriptionStatusList {
#Nullable
#SerializedName("subscriptions")
List<SubscriptionStatus> subscriptionStatuses;
SubscriptionStatusList(#Nullable List<SubscriptionStatus> subscriptionStatuses) {
this.subscriptionStatuses = subscriptionStatuses;
}
}
public static final String SUBSCRIPTIONS_KEY = "subscriptions";
public static final String SKU_KEY = "sku";
public static final String PURCHASE_TOKEN_KEY = "purchaseToken";
public static final String IS_ENTITLEMENT_ACTIVE_KEY = "isEntitlementActive";
public static final String WILL_RENEW_KEY = "willRenew";
public static final String ACTIVE_UNTIL_MILLISEC_KEY = "activeUntilMillisec";
public static final String IS_FREE_TRIAL_KEY = "isFreeTrial";
public static final String IS_GRACE_PERIOD_KEY = "isGracePeriod";
public static final String IS_ACCOUNT_HOLD_KEY = "isAccountHold";
// Local fields
#PrimaryKey(autoGenerate = true)
public int primaryKey = 0;
#Nullable
public String subscriptionStatusJson;
public boolean subAlreadyOwned;
public boolean isLocalPurchase;
// Remote fields
#Nullable
public String sku;
#Nullable
public String purchaseToken;
public Boolean isEntitlementActive;
public Boolean willRenew;
public Long activeUntilMillisec = 0L;
public Boolean isFreeTrial;
public Boolean isGracePeriod;
public Boolean isAccountHold;
/**
* Parse subscription data from Map and return null if data is not valid.
*/
#Nullable
public static List<SubscriptionStatus> listFromMap(Map<String, Object> map) {
List<SubscriptionStatus> subscriptions = new ArrayList<>();
List<Map<String, Object>> subList = null;
if (map.get(SUBSCRIPTIONS_KEY) instanceof ArrayList) {
subList = (ArrayList) map.get(SUBSCRIPTIONS_KEY);
}
if (subList == null) {
return null;
}
for (Map<String, Object> subStatus : subList) {
SubscriptionStatus subscriptionStatus = new SubscriptionStatus();
subscriptionStatus.sku = (String) subStatus.get(SKU_KEY);
subscriptionStatus.purchaseToken = (String) subStatus.get(PURCHASE_TOKEN_KEY);
subscriptionStatus.isEntitlementActive =
(Boolean) subStatus.get(IS_ENTITLEMENT_ACTIVE_KEY);
subscriptionStatus.willRenew = (Boolean) subStatus.get(WILL_RENEW_KEY);
subscriptionStatus.activeUntilMillisec =
(Long) subStatus.get(ACTIVE_UNTIL_MILLISEC_KEY);
subscriptionStatus.isFreeTrial = (Boolean) subStatus.get(IS_FREE_TRIAL_KEY);
subscriptionStatus.isGracePeriod = (Boolean) subStatus.get(IS_GRACE_PERIOD_KEY);
subscriptionStatus.isAccountHold = (Boolean) subStatus.get(IS_ACCOUNT_HOLD_KEY);
subscriptions.add(subscriptionStatus);
}
return subscriptions;
}
/**
* Parse subscription data from String and return null if data is not valid.
*/
#Nullable
public static List<SubscriptionStatus> listFromJsonString(String dataString) {
Gson gson = new Gson();
try {
SubscriptionStatusList subscriptionStatusList =
gson.fromJson(dataString, SubscriptionStatusList.class);
if (subscriptionStatusList != null) {
return subscriptionStatusList.subscriptionStatuses;
} else {
return null;
}
} catch (JsonSyntaxException e) {
return null;
}
}
/**
* Create a record for a subscription that is already owned by a different user.
*
* The server does not return JSON for a subscription that is already owned by
* a different user, so we need to construct a local record with the basic fields.
*/
public static SubscriptionStatus alreadyOwnedSubscription(String sku, String purchaseToken) {
SubscriptionStatus subscriptionStatus = new SubscriptionStatus();
subscriptionStatus.sku = sku;
subscriptionStatus.purchaseToken = purchaseToken;
subscriptionStatus.isEntitlementActive = false;
subscriptionStatus.subAlreadyOwned = true;
return subscriptionStatus;
}
#Override
public String toString() {
return "SubscriptionStatus{" +
"primaryKey=" + primaryKey +
", subscriptionStatusJson='" + subscriptionStatusJson + '\'' +
", subAlreadyOwned=" + subAlreadyOwned +
", isLocalPurchase=" + isLocalPurchase +
", sku='" + sku + '\'' +
", purchaseToken='" + purchaseToken + '\'' +
", isEntitlementActive=" + isEntitlementActive +
", willRenew=" + willRenew +
", activeUntilMillisec=" + activeUntilMillisec +
", isFreeTrial=" + isFreeTrial +
", isGracePeriod=" + isGracePeriod +
", isAccountHold=" + isAccountHold +
'}';
}
}
I don't understand it why I have to get NPE. Or if we get if from the server, why don't I get it with the first account (I even tested putting the purchase on pause for the first account) and it works.
PS. Initially in my play console, Account hold feature was not active, but later on, I activated the account hold and account pause feature. But still I get the same error just after switching to the second google account.
Every time when Java uses Boolean object in if statement it unwraps it to primitive which is boolean type with Boolean.booleanValue() method.
To fix the issue you have to change isAccountHold and isEntitlementActive types from Boolean to boolean.
If those fields have to be Boolean type then check them for null before:
public static boolean isAccountHold(SubscriptionStatus subscription) {
return subscription != null &&
(subscription.isEntitlementActive == null || !subscription.isEntitlementActive) &&
(subscription.isAccountHold != null || subscription.isAccountHold) &&
!subscription.subAlreadyOwned;
}
Related
I'm trying to write a custom function in hibernate to use ts_vector (postgres), my code so far:
public class PostgresSQLFTSFunction implements SQLFunction {
static final Logger LOG = LogManager.getLogger();
#Override
public boolean hasArguments() {
return true;
}
#Override
public boolean hasParenthesesIfNoArguments() {
return false;
}
#Override
public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
return new BooleanType();
}
#Override
public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException {
if (arguments == null || arguments.size() < 2) {
throw new IllegalArgumentException("The function must have at least 2 arguments");
}
String fragment, ftsConfig, field, value;
if (arguments.size() == 3) {
ftsConfig = (String) arguments.get(0);
field = (String) arguments.get(1);
value = (String) arguments.get(2);
fragment = "to_tsvector(" + ftsConfig + ", unaccent(" + field + ")) ## to_tsquery(" + ftsConfig + ", unaccent(" + value + "))";
} else {
field = (String) arguments.get(0);
value = (String) arguments.get(1);
fragment = "to_tsvector(unaccent(" + field + ")) ## " + "to_tsquery('" + value + ":*' )";
}
LOG.info(fragment);
return fragment;
}
}
My repo:
#Query(value = "from City c where fts_partial(c.name, :cityName) = true")
List<City> getPartialByName(#Param("cityName") String cityName);
And registering the function:
public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
#Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applySqlFunction("fts_partial", new PostgresSQLFTSFunction());
}
}
The output query generated by Hibernate is:
select city0_.id as id1_0_, city0_.created_at as created_2_0_, city0_.updated_at as updated_3_0_, city0_.version as version4_0_, city0_.lat as lat5_0_, city0_.lng as lng6_0_, city0_.name as name7_0_, city0_.state_id as state_id8_0_ from cities city0_ where to_tsvector(unaccent(city0_.name)) ## to_tsquery('?:*' )=true
The problem here is that to_tsquery('?:*' ) does not translate the question mark to the named param (cityName), because it is included in single quotes, but the single quote here is necessary, otherwise the query does not work.
For instance, the query that works is:
select city0_.id as id1_0_, city0_.created_at as created_2_0_, city0_.updated_at as updated_3_0_, city0_.version as version4_0_, city0_.lat as lat5_0_, city0_.lng as lng6_0_, city0_.name as name7_0_, city0_.state_id as state_id8_0_ from cities city0_ where to_tsvector(unaccent(city0_.name)) ## to_tsquery('vi:*')=true;
So, the cityName question mark should be translated by HQL to 'vi' in the above example.
How can I achieve that?
Thanks!
I have this class ( DoctorRegistrationTest.java ) and having the global variable doctorCode , doctorFirstName , doctorFamilyName )
#BeforeMethod(groups = {"BVT", "Regression"})
public void loadRmsPage() {
loadRmsProfile();
softAssert = new SoftAssert();
doctorRegistrationPage = new DoctorRegistrationPage(webDriver);
}
#Epic("RMS - Create Doctor")
#Feature("RMS - Create Doctor functionality")
#Story("AUT-688")
#Severity(SeverityLevel.BLOCKER)
#Test(description = "Positive : Doctor Creation ", groups = {"BVT", "Regression"})
public void createDoctorTestMethod() {
do {
doctorCode = String.valueOf(generateRandomNumber(1000, 9999));
} while (false && doctorRegistrationPage.verifyCreatedDoctor(doctorCode));
setDoctorRegistrationInformation();
createDoctor();
}
public void createDoctor() {
doctorRegistrationPage.loadDoctorRegistrationPage();
doctorRegistrationPage.fillDoctorNameInformation(doctorCode, doctorFirstName, doctorFamilyName, doctorFirstNameInArabic, doctorFamilyNameInArabic);
doctorRegistrationPage.fillDoctorGeneralInformation(dateOfBirth, joinDate, identityNo, expiryDate, gender, doctorTitle, employmentType, identityType);
doctorRegistrationPage.fillDoctorContactInformation(mobileNumber, companyEmail);
doctorRegistrationPage.fillDoctorOtherInformation(doctorInformationEnglish, doctorInformationArabic);
doctorRegistrationPage.fillDoctorTiming(followUpDays, slotDurationMinutes);
doctorRegistrationPage.fillDoctorHospitalsAndClinics(hospital, clinics);
doctorRegistrationPage.fillDoctorDefaultProcedure(defaultProcedur, consultationProcedure);
boolean result = doctorRegistrationPage.verifyCreatedDoctor(doctorCode);
LOG.info("Return value of verifyCreatedDoctor method " + result);
softAssert.assertTrue(result, "TEST FAILED - CREATED DOCTOR NOT LISTING IN THE GRID");
softAssert.assertAll();
doctorRegistrationPage.logOutUser();
}
public void setDoctorRegistrationInformation() {
readPropertiesFile();
setNames();
setNumberValues();
setDate();
}
public void setNames() {
doctorFirstName = "AUT DN " + getRandomStringName(4);
doctorFamilyName = "AUT DFN " + getRandomStringName(4);
companyEmail = getRandomStringName(5) + "#aut.com";
doctorInformationEnglish = getRandomStringName(6);
}
public String getRandomStringName(int randomStringLength) {
return RandomStringUtils.randomAlphabetic(randomStringLength).toLowerCase();
}
public int generateRandomNumber(int low, int high) {
return (new Random()).nextInt(high - low) + low;
}
}
I have another class ( DoctorScheduleTest.java ) and needs to pass doctorCode , doctorFirstName , doctorFamilyName from (DoctorRegistrationTest.java ) to doctorSchedulePage.selectDoctorDropdown(doctor); method, instead of hardcoding the detail. Must pass the value like this (" doctorCode: doctorFirstName doctorFamilyName )
private String doctor =" 8938: AUT DN gvgl AUT DFN wnrn ";
#BeforeMethod(groups = {"BVT", "Regression"})
public void loadRmsPage()
{
loadRmsProfile();
softAssert = new SoftAssert();
doctorSchedulePage = new DoctorSchedulePage(webDriver);
}
#Epic("RMS")
#Feature("RMS - Create Doctor Schedule functionality")
#Story("AUT-835")
#Severity(SeverityLevel.BLOCKER)
#Test(description = "Positive : Doctor Schedule Creation", groups = {"BVT", "Regression"})
public void doctorScheduleCreationTestMethod()
{
setTemplateName();
createInitialSchedule();
setSchedule();
saveTemplate();
setTemplate();
setDateRange();
generateSchedule();
}
public void createInitialSchedule()
{
doctorSchedulePage.loadDoctorScheduleDashboard();
doctorSchedulePage.selectHospitalDropDown(hospital);
doctorSchedulePage.selectClinicDropDown(clinic);
doctorSchedulePage.selectDoctorDropdown(doctor);
doctorSchedulePage.fillTemplate(scheduleTemplateName);
}
public void setSchedule()
{
doctorSchedulePage.sundaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.mondaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.tuesdaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.wednesdaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.thursdaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.fridaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
doctorSchedulePage.saturdaySchedule(startHourTime,startMinuteTime,startSchedule,endHourTime,endMinuteTime,endSchedule);
}
public void saveTemplate()
{
doctorSchedulePage.saveTemplate();
}
public void setTemplate()
{
doctorSchedulePage.selectTemplateDropdown(scheduleTemplateName);
}
public void setDateRange()
{
doctorSchedulePage.selectScheduleDate(scheduleStartDate,scheduleEndDate);
}
public void generateSchedule()
{
doctorSchedulePage.generateSchedule();
}
public int generateRandomNumber(int low, int high)
{
return (new Random()).nextInt(high - low) + low;
}
public void setTemplateName()
{
scheduleTemplateName = "Template " + getRandomStringName(3);
}
public String getRandomStringName(int randomStringLength)
{
return RandomStringUtils.randomAlphabetic(randomStringLength).toLowerCase();
}
}
DoctorSchedulePage.java ( selectDoctorDropdown method )
public void selectDoctorDropdown(String doctorcode)
{
selectValueFromDropDown(doctorDropdown, doctorcode);
}
BasePage.java (selectValueFromDropDown method )
protected void selectValueFromDropDown(WebElement element, String value) {
if (value != null && !value.isEmpty()) {
waitForElementToPresent(element);
Select dropdown = new Select(element);
LOG.info("Selected "+value);
dropdown.selectByVisibleText(value);
}
}
First of all, your question indicates, that you have an issue with passing a test data into tests. That should be addressed in the first place.
Since that is another topic (and a much bigger one) I would recommend a workaround, using a separate class, with a doctor's data.
public static class Doctor{
public static String FirstName;
public static String FamilyName;
Initialize the data in the setup and use is whenever you need.
As I said before, that is not the best solution, as testing data should be kept outside of the tests, but might be helpful for now.
I am using Microsoft Cognitive Services - Speech Recognition on an Android application. Everything works fine when the code is in my main activity, but when I want to move the part corresponding to speech recognition to a new class, it throws an error.
Here are the code samples:
In the main activity
int m_waitSeconds = 0;
MicrophoneRecognitionClient micClient = null;
FinalResponseStatus isReceivedResponse = FinalResponseStatus.NotReceived;
Boolean speechIntent = false;
SpeechRecognitionMode speechMode = SpeechRecognitionMode.ShortPhrase;
public enum FinalResponseStatus { NotReceived, OK }
/**
* Gets the primary subscription key
*/
public String getPrimaryKey() {
return this.getString(R.string.primaryKey);
}
/**
* Gets the secondary subscription key
*/
public String getSecondaryKey() {
return this.getString(R.string.secondaryKey);
}
/**
* Gets the LUIS application identifier.
* #return The LUIS application identifier.
*/
private String getLuisAppId() {
return this.getString(R.string.luisAppID);
}
/**
* Gets the LUIS subscription identifier.
* #return The LUIS subscription identifier.
*/
private String getLuisSubscriptionID() {
return this.getString(R.string.luisSubscriptionID);
}
/**
* Gets the default locale.
* #return The default locale.
*/
private String getDefaultLocale() {
return "en-us";
}
/**
* Handles the Click event of the _startButton control.
*/
private void StartButton_Click(View v) {
this.m_waitSeconds = this.speechMode == SpeechRecognitionMode.ShortPhrase ? 20 : 200;
if (this.micClient == null) {
if (this.speechIntent) {
this.WriteLine("--- Start microphone dictation with Intent detection ----");
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClientWithIntent(
this,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey(),
this.getLuisAppId(),
this.getLuisSubscriptionID());
}
else
{
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClient(
this,
this.speechMode,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey());
}
}
this.micClient.startMicAndRecognition();
}
public void onFinalResponseReceived(final RecognitionResult response) {
boolean isFinalDicationMessage = this.speechMode == SpeechRecognitionMode.LongDictation &&
(response.RecognitionStatus == RecognitionStatus.EndOfDictation ||
response.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout);
if (null != this.micClient && ((this.speechMode == SpeechRecognitionMode.ShortPhrase) || isFinalDicationMessage)) {
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
this.micClient.endMicAndRecognition();
}
if (isFinalDicationMessage) {
this.isReceivedResponse = FinalResponseStatus.OK;
}
Confidence cMax = Confidence.Low;
int iMax = 0;
if (!isFinalDicationMessage && response.Results.length != 0) {
for (int i = 0; i < response.Results.length; i++) {
//get the text with highest confidence:
if(response.Results[i].Confidence.getValue() > cMax.getValue()){
cMax = response.Results[i].Confidence;
iMax = i;
}
}
this.WriteLine(response.Results[iMax].DisplayText);
}
}
/**
* Called when a final response is received and its intent is parsed
*/
public void onIntentReceived(final String payload) {
this.WriteLine("--- Intent received by onIntentReceived() ---");
this.WriteLine(payload);
this.WriteLine();
}
public void onPartialResponseReceived(final String response) {
this.WriteLine("--- Partial result received by onPartialResponseReceived() ---");
this.WriteLine(response);
this.WriteLine();
}
public void onError(final int errorCode, final String response) {
this.WriteLine("--- Error received by onError() ---");
this.WriteLine("Error code: " + SpeechClientStatus.fromInt(errorCode) + " " + errorCode);
this.WriteLine("Error text: " + response);
this.WriteLine();
}
/**
* Called when the microphone status has changed.
* #param recording The current recording state
*/
public void onAudioEvent(boolean recording) {
if (!recording) {
this.micClient.endMicAndRecognition();
}
}
/**
* Writes the line.
*/
private void WriteLine() {
this.WriteLine("");
}
/**
* Writes the line.
* #param text The line to write.
*/
private void WriteLine(String text) {
System.out.println(text);
}
In a separate class
public class SpeechRecognition implements ISpeechRecognitionServerEvents
{
int m_waitSeconds = 0;
private MicrophoneRecognitionClient micClient = null;
private FinalResponseStatus isReceivedResponse =FinalResponseStatus.NotReceived;
private Boolean speechIntent = false;
private SpeechRecognitionMode speechMode=SpeechRecognitionMode.ShortPhrase;
public enum FinalResponseStatus { NotReceived, OK }
/**
* Gets the primary subscription key
*/
public String getPrimaryKey() {
return Integer.toString(R.string.primaryKey);
}
/**
* Gets the secondary subscription key
*/
public String getSecondaryKey() {
return Integer.toString(R.string.secondaryKey);
}
/**
* Gets the LUIS application identifier.
* #return The LUIS application identifier.
*/
private String getLuisAppId() {
return Integer.toString(R.string.luisAppID);
}
/**
* Gets the LUIS subscription identifier.
* #return The LUIS subscription identifier.
*/
private String getLuisSubscriptionID() {
return Integer.toString(R.string.luisSubscriptionID);
}
/**
* Gets the default locale.
* #return The default locale.
*/
private String getDefaultLocale() {
return "en-us";
}
public void startSpeechRecognition() {
this.m_waitSeconds = this.speechMode == SpeechRecognitionMode.ShortPhrase ? 20 : 200;
if (this.micClient == null) {
if (this.speechIntent) {
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClientWithIntent(
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey(),
this.getLuisAppId(),
this.getLuisSubscriptionID());
}
else
{
this.micClient = SpeechRecognitionServiceFactory.createMicrophoneClient(
this.speechMode,
this.getDefaultLocale(),
this,
this.getPrimaryKey(),
this.getSecondaryKey());
}
}
this.micClient.startMicAndRecognition();
}
public void endSpeechRecognition(){
this.micClient.endMicAndRecognition();
}
public void onFinalResponseReceived(final RecognitionResult response) {
boolean isFinalDicationMessage = this.speechMode == SpeechRecognitionMode.LongDictation &&
(response.RecognitionStatus == RecognitionStatus.EndOfDictation ||
response.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout);
if (null != this.micClient && ((this.speechMode == SpeechRecognitionMode.ShortPhrase) || isFinalDicationMessage)) {
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
this.micClient.endMicAndRecognition();
}
if (isFinalDicationMessage) {
this.isReceivedResponse = FinalResponseStatus.OK;
}
Confidence cMax = Confidence.Low;
int iMax = 0;
if (!isFinalDicationMessage && response.Results.length != 0) {
for (int i = 0; i < response.Results.length; i++) {
//get the text with highest confidence:
if(response.Results[i].Confidence.getValue() > cMax.getValue()){
cMax = response.Results[i].Confidence;
iMax = i;
}
}
System.out.println("Action to take: " + response.Results[iMax].DisplayText);
}
}
/**
* Called when a final response is received and its intent is parsed
*/
public void onIntentReceived(final String payload) {
System.out.println("--- Intent received by onIntentReceived() ---");
System.out.println(payload);
}
public void onPartialResponseReceived(final String response) {
System.out.println("--- Partial result received by onPartialResponseReceived() ---");
System.out.println(response);
}
public void onError(final int errorCode, final String response) {
System.err.println("--- Error received by onError() ---");
System.err.println("Error code: " + SpeechClientStatus.fromInt(errorCode) + " " + errorCode);
System.err.println("Error text: " + response);
}
/**
* Called when the microphone status has changed.
* #param recording The current recording state
*/
public void onAudioEvent(boolean recording) {
System.out.println("--- Microphone status change received by onAudioEvent() ---");
System.out.println("********* Microphone status: " + recording + " *********");
if (recording) {
System.out.println("Please start speaking.");
}
if (!recording) {
this.micClient.endMicAndRecognition();
}
}
}
You can clearly see that it is basically the same code but it gives me this error in the onError function after i call this.micClient.startMicAndRecognition();
:
Error code: LoginFailed -1910505470
I solved the problem.
I was getting a wrong Primary key in this line of code:
public String getPrimaryKey() {
return Integer.toString(R.string.primaryKey);
}
It is because the primary key is too long to be read by the processor as an integer then transformed to a String. I had to get the primary key from the main activity via getString(R.string.primaryKey) then pass it as a parameter to the constructor of the SpeechRecognition class.
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.
This question already has answers here:
When you call remove(object o) on an arraylist, how does it compare objects?
(4 answers)
Closed 8 years ago.
I want to remove particular bean object from ArrayList.
I am using remove and removeAll method for delete the object element from ArrayList, but not remove element.
for example, assume below code,
ArrayList<SystemDetailData> systemDetails = new ArrayList<SystemDetailData>();
SystemDetailData data = new SystemDetailData();
data.setId("1");
data.setName("abc");
data.setHost("192.168.1.2");
systemDetails.add(data);
data = new SystemDetailData();
data.setId("2");
data.setName("asd");
data.setHost("192.168.1.45");
systemDetails.add(data);
System.out.println("Before remove : " + systemDetails);
ArrayList<SystemDetailData> systemDetail = new ArrayList<SystemDetailData>();
SystemDetailData data = new SystemDetailData();
data.setId("1");
data.setName("abc");
data.setHost("192.168.1.2");
systemDetail.add(data);
System.out.println("Old data :" + systemDetail);
//Remove object from arraylist - method1
systemDetails.removeAll(systemDetail);
//Remove object from arraylist - method2
systemDetails.removeAll(systemDetail.getId());
systemDetails.removeAll(systemDetail.getName());
systemDetails.removeAll(systemDetail.getHost());
System.out.println("After remove : "+systemDetails);
Bean Class :
public class SystemDetailData extends BusinessData {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String DOMAIN_NAME = "domainName";
private static final String HOST_NAME = "hostName";
private static final String USER_NAME = "userName";
private static final String PASSWORD = "password";
private static final String INDEX = "index";
private BigInteger index;
private String domainName;
private String hostName;
private String userName;
private String password;
public BigInteger getIndex() {
return (BigInteger) get (INDEX);
}
public void setIndex(BigInteger index) {
set (INDEX, index);
this.index = index;
}
public String getDomainName() {
return (String) get(DOMAIN_NAME).toString();
}
public void setDomainName(String domainName) {
set (DOMAIN_NAME, domainName);
this.domainName = domainName;
}
public String getHostName() {
return (String) get (HOST_NAME);
}
public void setHostName(String hostName) {
set (HOST_NAME, hostName);
this.hostName = hostName;
}
public String getUserName() {
return (String) get (USER_NAME);
}
public void setUserName(String userName) {
set (USER_NAME, userName);
this.userName = userName;
}
public String getPassword() {
return (String) get (PASSWORD);
}
public void setPassword(String password) {
set (PASSWORD, password);
this.password = password;
}
#Override
public String toString() {
return "SystemDetailData [index=" + index + ", domainName="
+ domainName + ", hostName=" + hostName + ", userName="
+ userName + ", password=" + password + "]";
}
#Override
public String getKeyValue() {
String value = "";
if (index != null) {
value = value + "INDEX =" + index + ";";
}
if (domainName != null) {
value = value + "DOMAIN_NAME =" + domainName + ";";
}
if (userName != null) {
value = value + "USER_NAME =" + userName + ";";
}
if (hostName != null) {
value = value + "HOST_NAME =" + hostName + ";";
}
if (password != null) {
value = value + "PASSWORD =" + password + ";";
}
return value;
}
}
I got below output :
Before remove : [SystemDetailData [index=1, Name=abc, host=192.168.1.2], SystemDetailData [index=2, Name=asd, host=192.168.1.45]]
Old data : [SystemDetailData [index=1, Name=abc, host=192.168.1.2]]
After remove : [SystemDetailData [index=1, Name=abc, host=192.168.1.2], SystemDetailData [index=2, Name=asd, host=192.168.1.45]]
I want below output :
After remove : [SystemDetailData [index=2, Name=asd, host=192.168.1.45]]
If the SystemDetailData Class you have to implement hashcode and equals method. To expand my answer, In java when you want to delete an Object from a collection. Java check if the Object you want to delete is in this collection ( if Collection contains an Object which is equals to the one we want to delete). It uses the method equals. So we have to tell (explain) to Java what is for us the same Object: it can have the same name or the same id or another property ( attribute ). This is a reason why we have to implements equals (and hashcode)
Your SystemDetailData class needs to implement an equals method. When you call remove on the ArrayList, the code is doing something like:
ArrayList<SystemDetailData> items;
void remove(SystemDetailData itemToRemove) {
for ( int i = 0; i < items.size() ++i ) {
if ( items.get(i).equals(itemToRemove) ) {
items.remove(i);
break;
}
}
}
he
So unless the equals method returns true for the item you are passing into the remove method and an item in your collection, nothing wil be removed.
You need to decide exactly what the equals method should look like but if, for example, two items are the same if the ids are the same then you could just add a method to SystemDetailData like:
public boolean equals(Object other) {
SystemDetailData otherData = (SystemDetailData)other;
return otherData.getId() == this.getId();
}
Obviously you'll need to add checks for null, the type of other etc. but that should give you an idea of what the method needs to look like.