I am working on a java application with Spring and JDBC connection.
I did not code the application myself and I am kind of new to some of the frameworks and implications of this.
I traced the path of how sql statements are passed, however I am stuck at some point where I do not find any details on the method that is called and the class it belongs to.
The method is imported via import de.dit.icr.frontend.ProxyBean;
Basically all queries are contained in a single "query.xml" file, that is passed into a "ProxyBean" object, which is then fed with the parameters map and then a "getStatement()" method is called that returns the prepared query string.
What I would like to do is to split the query.xml file into single sql files (one for each query) and implement a new method instead of the proxyBean.getStatement(), that would still take the parameters map, the name of the query, and prepare the statement.
In order to do that, I require your light on something:
- where does this ProxyBean class come from? From an external library, and if so, which one?
- Which method, which library could I use to create a string of an sql prepared statement from a sql file and a parameters map?
Thanks a lot for your help!
Here is a simplified view of the code:
import de.dit.icr.frontend.ProxyBean;
import de.dit.icr.util.Url;
import de.dit.itsales.dbi.util.DBUtil;
import de.dit.itsales.dbi.util.Log;
public class IASAdapterImpl implements IASAdapter {
private static final String[] QUERY_FILES = {"query.xml"};
private static final String RELATIVE_PATH_TO_QUERY_FILE = "queries";
public IASAdapterImpl() {
init();
}
private void init() {
String key = "queries";
String pathToQueryFile = DBUtil.getInstance().getConfigDir() + RELATIVE_PATH_TO_QUERY_FILE;
Url.register(key, pathToQueryFile);
createProxyBean();
}
public synchronized String getQuery(String queryName, Map<String,String> queryVariables, boolean resolveNames) {
ProxyBean proxyBean = createProxyBean();
setParameter(queryVariables, proxyBean);
String temp = proxyBean.getStatement(queryName, resolveNames);
return temp;
}
private ProxyBean createProxyBean() {
ProxyBean bean = new ProxyBean();
for (int i = 0; i < QUERY_FILES.length; i++) {
bean.setQuerySet(QUERY_FILES[i]);
}
return bean;
}
private void setParameter(Map<String,String> map, ProxyBean bean) {
if(map == null || map.isEmpty()) {
return;
}
for (Map.Entry<String,String> entry : map.entrySet()) {
String key = entry.getKey();
bean.set(key, entry.getValue());
}
}
Sample of query.xml:
<query name = "alle-fonds"><![CDATA[
select fondsnummer,
spokid,
mfnummer,
fondsname,
bewertungsdatum,
letztebewertung,
hauptfonds,
performancegraphrelevant
from rep.v_alle_fonds where anwender_login = '${loginname}'
and sprache = lower('${sprache}')
order by mfnummer
]]></query>
Related
I'm working on some webservices, which I'm implementing with hibernate. The issue is that I need to access the names of the entity tables (say, those in #Table("Table_A")).
The code is generated, so I cannot alter the entity classes themselves to give me what I need.
This is what I was doing so far:
public static
<T extends Entity<K>, K extends Serializable>
String getTableName(Class<T> objClass) {
Table table = objClass.getAnnotation(Table.class);
return (table != null)? table.name() : null;
}
However, after some research I discovered that reflection is not the best performance-wise, and since this method will be called a lot I'm looking for another way to go at it.
I'm trying to follow the advice given here:
Performance of calling Method/Field.getAnnotation(Class) several times vs. Pre-caching this data in a Map.
This is what I came up with:
public final class EntityUtils {
private static HashMap<String, String> entityCache;
private EntityUtils() {
entityCache = new HashMap<String, String>();
}
public static
<T extends Entity<K>, K extends Serializable>
String getTableName_New(Class<T> objClass) {
String tableName = entityCache.get(objClass.getCanonicalName());
if (tableName == null) {
Table table = objClass.getAnnotation(Table.class);
if (table != null) {
tableName = table.name();
entityCache.put(objClass.getCanonicalName(), tableName);
}
}
return tableName;
}
}
However, I'm not sure about this. Is it a good idea to cache reflection data in a static map? Is there any alternative way to accomplish this?
Ideally, I would use a Guava cache, with weak keys, that way you're not keeping any references to the class object in case you use some advanced ClassLoader magic.
LoadingCache<Class<?>, String> tableNames = CacheBuilder.newBuilder()
.weakKeys()
.build(
new CacheLoader<Class<?>, String>() {
public String load(Class<?> key) {
Table table = objClass.getAnnotation(Table.class);
return table == null ? key.getSimpleName() : table.name();
}
});
Usage:
String tablename = tableNames.get(yourClass);
See: Caches Explained
On the other hand: annotations are cached by the JDK also, so your previous approach is probably fine
I'm using Hibernate and QueryDSL along with PostgreSQL on a Spring application, and face some performance issues with my filtered lists. Using the StringPath class, I'm calling either startsWithIgnoreCase, endsWithIgnoreCase or containsIgnoreCase.
It appears the generated query has the following where clause :
WHERE lower(person.firstname) LIKE ? ESCAPE '!'
Using the lower, the query is not taking advantage of the Postgres indexes. On a dev Database, queries take up to 1sec instead of 10ms with the ILIKE keyword.
Is there a way to get a Predicate using Postgres' ILIKE, as Ops doesn't seem to provide it?
Thanks
I've got exactly the same issue - lower(column) causes wrong pg statistics calculation and request is planned not efficiently, ilike solves the problem. I hadn't understood what parts of OP's answer are relevant to solution so reinvented the same approach, but a bit shorter.
Introduce new dialect with my_ilike function and it's implementation:
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL9Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new SQLFunctionTemplate(BooleanType.INSTANCE, "(?1 ilike ?2)"));
}
}
Specify this dialect to be used by Hibernate (I use Java config):
Properties props = new Properties();
props.setProperty("hibernate.dialect", "com.example.ExtendedPostgresDialect");
factory.setJpaProperties(props);
That's it, now you can use it:
BooleanTemplate.create("function('my_ilike', {0}, {%1%})", stringPath, value).isTrue();
Had to update this :
We found a way to create the needed Postgres operators by registering a SQL function using ilike, in our custom Hibernate Dialect.
Example with ilike :
//Postgres Constants Operators
public class PostgresOperators {
private static final String NS = PostgresOperators.class.getName();
public static final Operator<Boolean> ILIKE = new OperatorImpl<>(NS, "ILIKE");
}
//Custom JPQLTemplates
public class PostgresTemplates extends HQLTemplates {
public static final PostgresTemplates DEFAULT = new PostgresTemplates();
public PostgresTemplates() {
super();
add(PostgresOperators.ILIKE, "my_ilike({0},{1})");
}
}
Specify the JPQLTemplates when using jpaquery
new JPAQuery(entityManager, PostgresTemplates.DEFAULT);
now it gets tricky, we couldn't use ilike directly, there is an issue with an "ilike" keyword already registered, so we made an ilike function and registered it to a custom spring hibernate Dialect.
Our application.yml specifying :
#SEE JPA http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.data.jpa:com.example.customDialect.config.database.ExtendedPostgresDialect
Then
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL82Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new PostgreSQLIlikeFunction());
}
}
We tried to use the registerKeyword("ilike"), didn't work, we stayed with our function and the following implementation.
public class PostgreSQLIlikeFunction implements SQLFunction {
#Override
public Type getReturnType(Type columnType, Mapping mapping)
throws QueryException {
return new BooleanType();
}
#SuppressWarnings("unchecked")
#Override
public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) throws QueryException {
if (args.size() != 2) {
throw new IllegalArgumentException(
"The function must be passed 2 arguments");
}
String str1 = (String) args.get(0);
String str2 = (String) args.get(1);
return str1 + " ilike " + str2;
}
#Override
public boolean hasArguments() {
return true;
}
#Override
public boolean hasParenthesesIfNoArguments() {
return false;
}
}
That's pretty much it, now we can use ILIKE the following way :
BooleanOperation.create(PostgresOperators.ILIKE, expression1, expression2).isTrue()
I've got a pretty simple script that simply accesses a resources properties via a ValueMap. Except for some reason I keep getting an unexpected token error were the if statement starts. This has to be something I'm just overlooking.
public class headerComponent{
ValueMap property = resource.adaptTo(ValueMap.class);
if(property != null) {
pageHeader = property.get("pageHeader", "");
}
}
Any ideas? Thanks for the help.
Because you are using if direct inside your class. This should be inside a function.
For Ex:
public class headerComponent{
ValueMap property = resource.adaptTo(ValueMap.class);
public void getMeProp()
{
if(property != null) {
pageHeader = property.get("pageHeader", "");
}
}
}
If you want to return your string then use public String getMeProp() and in the end of the function return pageHeader. Depends how you want to implement.
A new java component that is suppose to send along a list of pre-define variable to external party. User will then able to define which variable (a fixed set of variable) they want to send via a xml property file
Problem is: The pre-define variable is inside a class, and have business logic together with it, which i can't change or tap into (part of external api). eg as follow:
public class DataColumn implement java.io.Serializable{
public static final String _actionID = "ActionID";
public static final String _actionName = "ActionName";
public static final String _actionDesc = "ActionDescription";
public static final DataColumn ActionDesc = new DataColumn (_actionDesc);
public static final DataColumn ActionID = new DataColumn (_actionID);
public static final DataColumn ActionName = new DataColumn (_actionName);
....and about 100 other variale more
protected WebMediaReportColumn(java.lang.String value) {
_value_ = value;
_table_.put(_value_,this);
}
}
user will define in the xml file like following:
<interface>
<fields isRequired="true">
<field>ActionID</field>
<field>ActionName</field>
<field>ActionDescription</field>
</fields>
</interface>
In order to set which variable to send across, the code looks like following:
interface.setColumns(new DataColumn[] {
DataColumn.ActionID, DataColumn.ActionName, DataColumn.ActionDesc
}
);
Question is: how best to write a program that can base on what the user define in a property file, and create the Datacolumn[] Array accordingly? Without using If else block which is too long and hard to maintain.
Write all these statements in a property file.
actionID = ActionID
actionName = ActionName
actionDesc = ActionDescription
/*... and so on */
In your code create an Properties object and load this file into it. Create an String array and populate the values from this properties object.
Properties p = new Properties();
/*...load the file...*/
String []columnData = new String[p.keySet().size()];
int i=0;
for(Object str : p.keySet()) {
columnData[i++]=(String)p.getProperty((String)str);
}
/*now call the method and pass the array*/
interface.setColumns(columnData);
I am new to OGNL. I am trying to write OGNL expressions in core java to retrieve properties/call methods.
Here is my test class.It has a List of keys and a Map which uses these keys to store values.
Please see below
package ognl.test;
import java.util.List;
import java.util.Map;
public class OGNLTestProg {
List<String> keys = null;
Map<String, Object> data = null;
public OGNLTestProg(List<String> keys, Map<String, Object> data){
this.keys = keys;
this.data = data;
}
public List<String> getKeys(){
return keys;
}
public Object getData(String key){
return data.get(key);
}
}
Here is the test program that instantiates an object of the above class and uses OGNL to call some methods.
package ognl.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ognl.Ognl;
public class Test {
public static void main(String[] args) throws Exception {
String str1 = "1";
String str2 = "2";
List<String> keys = new ArrayList<String>();
keys.add(str1);
keys.add(str2);
User u1 = new User();
u1.setFirstName("x");
u1.setLastName("y");
User u2 = new User();
u2.setFirstName("x1");
u2.setLastName("y1");
Map<String, Object> data = new HashMap<String, Object>();
data.put(str1, u1);
data.put(str2, u2);
OGNLTestProg o = new OGNLTestProg(keys, data);
/**
#{
#outerObj = #this,
'users': getKeys().
{
#{
#user = outerObj.getData(#this),
#{
'firstName': user.getFirstName(),
'lastName':user.getLastName()
}
}
}
}
*/
Object expression1 = Ognl.parseExpression("#{"+
"#outerObj = #this,"+
"'users': getKeys()."+
"{"+
"#{"+
"#user = outerObj.getData(#this),"+
"#{ 'firstName': user.getFirstName(),"+
"'lastName':user.getLastName()"+
"}"+
"}" +
"}"+
"}");
Map<String,Object> map = (Map<String,Object>)Ognl.getValue(expression1, o);
}
}
User is a custom class that has firstName and lastName as properties.
What I am trying to achieve using the OGNL expr is to iterate the list, retrieve each key and then pass that key to the map to retrieve the value (User object) and then call some property on that object.
While I am able to iterate the list using
'users': getKeys().{
//I need to access the getData() method of the root object here passing the current #this object
}
My OGNL expression throws the following error
Exception in thread "main" ognl.NoSuchPropertyException: java.lang.String.outerObj
Please help. I found tons of stuff on google on using OGNL with struts2 tags, but there's nothing much on its usage to access object properties like above.
Regards,
Suv
If I were going to implement the functionality it looks like you want then I'd probably use a google guava Table object to create the multiple indexed user object which you can then retrieve with a single simple map.get(key) call.
What you have in your example is even matched exactly in the guava Table wiki tutorial on the API. You're making it more complicated than it has to be otherwise. ;)