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!
Related
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;
}
I have read all similar question but nothing help.
how to access arraylist from another class without "return"
Test Fail is not returning failedtest
As I have Assert.fail(); under same method which I need return value.
Please help me find solution for if any alternative way to access arraylist .
public class FrontPage extends SeleniumUtils implements IHomePage {
public List<String> failedtest = new ArrayList<String>();
public List<String> CheckSummaryExposure(WebDriver driver, String actualView, String viewName) throws InterruptedException {
String[] actualViews = actualView.split(",");
List<String> views = new ArrayList<>();
boolean flag = false;
for (int i = 0; i < actualViews.length; i++) {
if (views.get(i).equals(actualViews[i].trim().toString())) {
Add_Log.info("Successfully displayed " + viewName);
Reporter.log("Successfully displayed " + viewName);
} else {
Add_Log.info(" filter criteria is not displayed " + viewName);
Reporter.log(" filter criteria is not displayed " + viewName);
failedtest.add(" filter criteria is not displayed " + viewName);
flag = true;
}
}
if (flag) {
TestResultStatus.Testfail = true;
// Test Fail is not returning failedtest
Assert.fail();
} else {
Add_Log.info("Successfully all filter);
Reporter.log("Successfully all filter);
}
System.out.println("PRINT FAIL SENTENCE");
System.out.println(failedtest);
return failedtest;
}
other class [Sanity_TC] to call FrontPage class, method CheckSummaryExposure with return failedtest
public class Sanity_TC extends SuiteBase {
static public HashMap<String, String> Remark = new HashMap<>();
List<String> failedtest =null;
#Test(dataProvider = "SanityTCTest", dataProviderClass = utility.Xlsdataprovider.class, groups = "Dashboard", alwaysRun = true)
public void Sanity_TC015(LinkedHashMap<String, String> data) throws InterruptedException, SQLException {
String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
loadWebBrowser();
objLoginPage.login(getDriver(), username, password, URLs.get(Key), Instance);
String result = String.join("-",FP.CheckSummaryExposure(getDriver(), actualViews, viewName));
Remark.put(methodName, result);
https://github.com/FoundationDB/sql-parser
How to use this library to parse a query (can be very complex) and retrieve the list of every table in that query.
The queries can be long and complex for example :
SELECT LINK.instance_id,
LINK.fk_rte_pnt_start,
LINK.fk_rte_pnt_end,
LINK.depart_time_local_expect,
LINK.arrvl_time_local_expect,
LINK.depart_time_utc_expctd,
LINK.arrvl_time_utc_expctd,
LINK.fk_mepc_trnsprt_mode,
LINK.mepc_link_id,
LINK.rkst_carrier_cd,
LINK.water_land_mode,
LINK.fk_rkstves_part_vehicle,
LINK.rkstves_part_vehicle,
LINK.vehicle_voyg_num,
LINK.fk_route,
LINK.routng_type,
LINK.is_out_of_cntrct_scope,
STRT.point_seq,
STRT.fk_geo_site DEP_SITE_CD,
ENDP.fk_geo_site ARR_SITE_CD,
STRT.geo_site DEP_SITE_CD_X,
ENDP.geo_site ARR_SITE_CD_X
FROM (SELECT instance_id,
fk_rte_pnt_start,
fk_rte_pnt_end,
depart_time_local_expect,
arrvl_time_local_expect,
depart_time_utc_expctd,
arrvl_time_utc_expctd,
fk_mepc_trnsprt_mode,
mepc_link_id,
rkst_carrier_cd,
water_land_mode,
fk_rkstves_part_vehicle,
rkstves_part_vehicle,
vehicle_voyg_num,
fk_route,
routng_type,
is_out_of_cntrct_scope
FROM codsbrk.gcss_route_link
WHERE fk_route = ?) LINK
LEFT OUTER JOIN codsbrk.gcss_route_point STRT
ON STRT.instance_id = LINK.fk_rte_pnt_start
LEFT OUTER JOIN codsbrk.gcss_route_point ENDP
ON ENDP.instance_id = LINK.fk_rte_pnt_end
ORDER BY STRT.point_seq
WITH UR
and
SELECT MIRL.invoice_req_line_id,
MIRL.collection_office,
MIRL.prepaid_collect,
MIRL.item_code,
MIRL.line_amount_quoted,
MIRL.currency_code,
MIRL.unit_price_quoted,
MIRL.quantity,
MIRL.owner_of_income
FROM codsbrk.mlis_invoice MIR
INNER JOIN codsbrk.mlis_invoice_line MIRL
ON MIR.tpdoc_no = MIRL.tpdoc_no
AND MIR.invoice_req_id = MIRL.invoice_req_id
WHERE MIR.tpdoc_no = ?
AND MIR.invoice_status = ?
WITH UR
The solution was provided by Nathan Williams
code here : https://gist.github.com/nathanlws/f71000943777297c7cfb
can be found here !!!
http://community.foundationdb.com/questions/4418/parsing-the-table-names-from-complex-queries.html#answer-4419
Quoting Nathan Williams :
Switching to looking for FromTable will allow you to catch the remaining tables that aren't directly in the FromList (e.g. subqueries, joins).
import com.foundationdb.sql.parser.*;
import com.foundationdb.sql.StandardException;
public class TableFinder {
public static void main(String[] args) throws Exception {
SQLParser parser = new SQLParser();
for(String sql : args) {
StatementNode node = parser.parseStatement(sql);
node.accept(new FromTablePrinter());
}
}
public static class FromTablePrinter implements Visitor {
public Visitable visit(Visitable node) throws StandardException {
if(node instanceof FromTable) {
FromTable ft = (FromTable)node;
TableName name = ft.getOrigTableName();
String alias = ft.getCorrelationName();
if(name != null) {
System.out.print(name);
if(alias != null) {
System.out.print(" AS " + alias);
}
System.out.println();
} else if (alias != null) {
String type = node.getClass().getSimpleName();
System.out.println(type + " AS " + alias);
}
}
return node;
};
public boolean visitChildrenFirst(Visitable node) {
return false;
}
public boolean stopTraversal() {
return false;
}
public boolean skipChildren(Visitable node) {
return false;
}
}
}
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.
I use mybatis to perform sql queries in my project. I need to intercept sql query before executing to apply some changed dynamically. I've read about #Interseptors like this:
#Intercepts({#Signature(type= Executor.class, method = "query", args = {...})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
}
}
And it really intercepts executions, but there is no way to change sql query since appropriate field is not writable. Should I build new instance of whole object manually to just replace sql query? Where is the right place to intercept query execution to change it dynamically? Thank.
I hope it will help you:
#Intercepts( { #Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class
})
})
public class SelectCountSqlInterceptor2 implements Interceptor
{
public static String COUNT = "_count";
private static int MAPPED_STATEMENT_INDEX = 0;
private static int PARAMETER_INDEX = 1;
#Override
public Object intercept(Invocation invocation) throws Throwable
{
processCountSql(invocation.getArgs());
return invocation.proceed();
}
#SuppressWarnings("rawtypes")
private void processCountSql(final Object[] queryArgs)
{
if (queryArgs[PARAMETER_INDEX] instanceof Map)
{
Map parameter = (Map) queryArgs[PARAMETER_INDEX];
if (parameter.containsKey(COUNT))
{
MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
BoundSql boundSql = ms.getBoundSql(parameter);
String sql = ms.getBoundSql(parameter).getSql().trim();
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),
getCountSQL(sql), boundSql.getParameterMappings(),
boundSql.getParameterObject());
MappedStatement newMs = copyFromMappedStatement(ms,
new OffsetLimitInterceptor.BoundSqlSqlSource(newBoundSql));
queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
}
}
}
// see: MapperBuilderAssistant
#SuppressWarnings({ "unchecked", "rawtypes" })
private MappedStatement copyFromMappedStatement(MappedStatement ms,
SqlSource newSqlSource)
{
Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms
.getId(), newSqlSource, ms.getSqlCommandType());
builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
// setStatementTimeout()
builder.timeout(ms.getTimeout());
// setParameterMap()
builder.parameterMap(ms.getParameterMap());
// setStatementResultMap()
List<ResultMap> resultMaps = new ArrayList<ResultMap>();
String id = "-inline";
if (ms.getResultMaps() != null)
{
id = ms.getResultMaps().get(0).getId() + "-inline";
}
ResultMap resultMap = new ResultMap.Builder(null, id, Long.class,
new ArrayList()).build();
resultMaps.add(resultMap);
builder.resultMaps(resultMaps);
builder.resultSetType(ms.getResultSetType());
// setStatementCache()
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
return builder.build();
}
private String getCountSQL(String sql)
{
String lowerCaseSQL = sql.toLowerCase().replace("\n", " ").replace("\t", " ");
int index = lowerCaseSQL.indexOf(" order ");
if (index != -1)
{
sql = sql.substring(0, index);
}
return "SELECT COUNT(*) from ( select 1 as col_c " + sql.substring(lowerCaseSQL.indexOf(" from ")) + " ) cnt";
}
#Override
public Object plugin(Object target)
{
return Plugin.wrap(target, this);
}
#Override
public void setProperties(Properties properties)
{
}
}
You may consider using a string template library (eg Velocity, Handlebars, Mustache) to help you
As of to date, there is even MyBatis-Velocity (http://mybatis.github.io/velocity-scripting/) to help you to do scripting for the sql.
Depending on the changes you want to make, you may want to use the dynamic sql feature of mybatis 3