我们目前正在研究从Toplink 2.1-60f
升级到EclipseLink 2.6
的最佳方式。该项目有点大,大部分手动工作都必须在我们使用NativeQuery
的部分代码中完成。 Query.getResultList()
结果在两个JPA实现之间有所不同,因为TopLink返回List<Vector>
,另一方面EclipseLink
返回List<Object[]>
。遗憾的是,代码中充斥着List<Vector>
个引用。
解决方案的一部分是将list数组的结果转换为向量列表。我没有手动在所有地方进行此操作,而是认为我们可以使用 AspectJ 来拦截getResultList()
调用并转换返回值。这是一个可行的解决方案?有人实施过类似的解决方案我们正在使用 Maven 作为我们的构建工具。
提前致谢!
答案 0 :(得分:0)
我的建议是:使用一个好的IDE并重构你的代码!
但是因为你要求AOP解决方案,这里是一个自洽的AspectJ示例。由于我从未使用过JPA,因此我只是将您的情况重新创建为一个小抽象。
具有大量虚拟方法的抽象Query
基础实现:
package de.scrum_master.persistence;
import java.util.*;
import javax.persistence.*;
public abstract class MyBaseQueryImpl implements Query {
@Override public int executeUpdate() { return 0; }
@Override public int getFirstResult() { return 0; }
@Override public FlushModeType getFlushMode() { return null; }
@Override public Map<String, Object> getHints() { return null; }
@Override public LockModeType getLockMode() { return null; }
@Override public int getMaxResults() { return 0; }
@Override public Parameter<?> getParameter(String arg0) { return null; }
@Override public Parameter<?> getParameter(int arg0) { return null; }
@Override public <T> Parameter<T> getParameter(String arg0, Class<T> arg1) { return null; }
@Override public <T> Parameter<T> getParameter(int arg0, Class<T> arg1) { return null; }
@Override public <T> T getParameterValue(Parameter<T> arg0) { return null; }
@Override public Object getParameterValue(String arg0) { return null; }
@Override public Object getParameterValue(int arg0) { return null; }
@Override public Set<Parameter<?>> getParameters() { return null; }
@Override public Object getSingleResult() { return null; }
@Override public boolean isBound(Parameter<?> arg0) { return false; }
@Override public Query setFirstResult(int arg0) { return null; }
@Override public Query setFlushMode(FlushModeType arg0) { return null; }
@Override public Query setHint(String arg0, Object arg1) { return null; }
@Override public Query setLockMode(LockModeType arg0) { return null; }
@Override public Query setMaxResults(int arg0) { return null; }
@Override public <T> Query setParameter(Parameter<T> arg0, T arg1) { return null; }
@Override public Query setParameter(String arg0, Object arg1) { return null; }
@Override public Query setParameter(int arg0, Object arg1) { return null; }
@Override public Query setParameter(Parameter<Calendar> arg0, Calendar arg1, TemporalType arg2) { return null; }
@Override public Query setParameter(Parameter<Date> arg0, Date arg1, TemporalType arg2) { return null; }
@Override public Query setParameter(String arg0, Calendar arg1, TemporalType arg2) { return null; }
@Override public Query setParameter(String arg0, Date arg1, TemporalType arg2) { return null; }
@Override public Query setParameter(int arg0, Calendar arg1, TemporalType arg2) { return null; }
@Override public Query setParameter(int arg0, Date arg1, TemporalType arg2) { return null; }
@Override public <T> T unwrap(Class<T> arg0) { return null; }
}
唯一缺少的方法是getResultList()
,所以现在让我们为它提供两种不同的实现,扩展抽象基础实现:
具体Query
实施返回List<Vector>
:
这会模拟您的TopLink课程。
package de.scrum_master.persistence;
import java.util.*;
public class VectorQuery extends MyBaseQueryImpl {
@Override
public List getResultList() {
List<Vector<String>> resultList = new ArrayList<>();
Vector<String> result = new Vector<>();
result.add("foo"); result.add("bar");
resultList.add(result);
result = new Vector<>();
result.add("one"); result.add("two");
resultList.add(result);
return resultList;
}
}
具体Query
实施返回List<Object[]>
:
这模拟您的EclipseLink类。
package de.scrum_master.persistence;
import java.util.*;
public class ArrayQuery extends MyBaseQueryImpl {
@Override
public List getResultList() {
List<Object[]> resultList = new ArrayList<>();
Object[] result = new Object[] { "foo", "bar" };
resultList.add(result);
result = new Object[] { "one", "two" };
resultList.add(result);
return resultList;
}
}
驱动程序应用程序:
应用程序创建两个具体子类型的查询,每次假设列表元素都是向量。
package de.scrum_master.app;
import java.util.*;
import de.scrum_master.persistence.*;
public class Application {
public static void main(String[] args) {
List<Vector<?>> resultList;
resultList = new VectorQuery().getResultList();
for (Vector<?> result : resultList)
System.out.println(result);
resultList = new ArrayQuery().getResultList();
for (Vector<?> result : resultList)
System.out.println(result);
}
}
没有方面的控制台日志:
[foo, bar]
[one, two]
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.util.Vector
at de.scrum_master.app.Application.main(Application.java:15)
嗯,哦!这正是你的问题,对吗?如果我们绝对拒绝重构,那么我们能做些什么呢?我们滥用AOP来修补遗留代码。 (请不要这样做,但如果你绝对想要,你可以。)
AspectJ查询结果适配器:
无视原始类型和其他丑陋的东西的使用,这是我的概念证明:
package de.scrum_master.aspect;
import java.util.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class QueryResultAdapter {
@Around("call(* javax.persistence.Query.getResultList())")
public List<Vector> transformQueryResult(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println(thisJoinPoint);
List result = (List) thisJoinPoint.proceed();
if (result != null && result.size() > 0 && result.get(0) instanceof Vector)
return result;
System.out.println("Transforming arrays to vectors");
List<Vector> transformedResult = new ArrayList<Vector>();
for (Object[] arrayItem : (List<Object[]>) result)
transformedResult.add(new Vector(Arrays.asList(arrayItem)));
return transformedResult;
}
}
带方面的控制台日志:
call(List de.scrum_master.persistence.VectorQuery.getResultList())
[foo, bar]
[one, two]
call(List de.scrum_master.persistence.ArrayQuery.getResultList())
Transforming arrays to vectors
[foo, bar]
[one, two]
Etvoilà - 你可以做丑陋的东西以及其他不是用AOP发明的东西。 ;-)