You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/09/24 21:32:23 UTC
svn commit: r1001040 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/access/jdbc/
main/java/org/apache/cayenne/access/trans/
main/java/org/apache/cayenne/ejbql/
main/java/org/apache/cayenne/ejbql/parser/ ...
Author: aadamchik
Date: Fri Sep 24 19:32:22 2010
New Revision: 1001040
URL: http://svn.apache.org/viewvc?rev=1001040&view=rev
Log:
CAY-1213 Cayenne should support enum types in qualifier statements/expression handling
* CAY-1213-ejbql.patch by Andrei Veprev
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLConstant.java
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/Util.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/ConstQueryTest.java
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java Fri Sep 24 19:32:22 2010
@@ -32,6 +32,7 @@ import org.apache.cayenne.ejbql.EJBQLBas
import org.apache.cayenne.ejbql.EJBQLException;
import org.apache.cayenne.ejbql.EJBQLExpression;
import org.apache.cayenne.ejbql.parser.AggregateConditionNode;
+import org.apache.cayenne.ejbql.parser.EJBQLConstant;
import org.apache.cayenne.ejbql.parser.EJBQLDecimalLiteral;
import org.apache.cayenne.ejbql.parser.EJBQLEquals;
import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable;
@@ -685,6 +686,18 @@ public class EJBQLConditionTranslator ex
}
@Override
+ public boolean visitConst(EJBQLExpression expression) {
+ Object constValue = ((EJBQLConstant) expression).getValue();
+ String constBoundName = context.bindParameter(constValue);
+ context.append(" #bind($").append(constBoundName).append(")");
+
+ if (constValue instanceof Enum<?>) {
+ processEnumParameter(expression, constBoundName, (Enum<?>) constValue);
+ }
+ return true;
+ }
+
+ @Override
public boolean visitIntegerLiteral(EJBQLIntegerLiteral expression) {
if (expression.getText() == null) {
context.append("null");
@@ -810,6 +823,60 @@ public class EJBQLConditionTranslator ex
return false;
}
+ private AttributeProperty getParentExpressionLastPathChildAttribute(
+ EJBQLExpression expression) {
+ Node parent = ((SimpleNode) expression).jjtGetParent();
+ EJBQLPathAnaliserTranslator translator = new EJBQLPathAnaliserTranslator(context);
+ parent.visit(translator);
+ translator.visitPath(parent, parent.getChildrenCount());
+
+ String id = translator.idPath;
+ if (id != null) {
+ ClassDescriptor descriptor = context.getEntityDescriptor(id);
+ if (descriptor == null) {
+ throw new EJBQLException("Unmapped id variable: " + id);
+ }
+ String pathChunk = translator.lastPathComponent;
+ Property property = descriptor.getProperty(pathChunk);
+ if (property instanceof AttributeProperty) {
+ return (AttributeProperty) property;
+ }
+ }
+ return null;
+ }
+
+ private Integer getParentExpressionSqlType(EJBQLExpression expression) {
+ AttributeProperty lastPathAttribute = getParentExpressionLastPathChildAttribute(expression);
+ return lastPathAttribute == null ? null : lastPathAttribute
+ .getAttribute()
+ .getDbAttribute()
+ .getType();
+ }
+
+ private String getParentExpressionSqlTypeName(EJBQLExpression expression) {
+ AttributeProperty lastPathAttribute = getParentExpressionLastPathChildAttribute(expression);
+ if (lastPathAttribute != null) {
+ String atrType = lastPathAttribute.getAttribute().getType();
+ return TypesMapping.getSqlNameByType(TypesMapping.getSqlTypeByJava(atrType));
+ }
+ return null;
+ }
+
+ private void processEnumParameter(
+ EJBQLExpression expression,
+ String boundName,
+ Enum<?> value) {
+ context.pushMarker("@processEnumParameter", true);
+ Integer sqlType = getParentExpressionSqlType(expression);
+ if (sqlType != null && TypesMapping.isNumeric(sqlType)) {
+ context.rebindParameter(boundName, value.ordinal());
+ }
+ else {
+ context.rebindParameter(boundName, value.name());
+ }
+ context.popMarker();
+ }
+
private void processParameter(String boundName, EJBQLExpression expression) {
Object object = context.getBoundParameter(boundName);
@@ -838,38 +905,13 @@ public class EJBQLConditionTranslator ex
if (object != null) {
context.append(" #bind($").append(boundName).append(")");
+ if (object instanceof Enum<?>) {
+ processEnumParameter(expression, boundName, (Enum<?>) object);
+ }
}
else {
-
- String type = null;
- Node parent = ((SimpleNode) expression).jjtGetParent();
-
context.pushMarker("@processParameter", true);
-
- EJBQLPathAnaliserTranslator translator = new EJBQLPathAnaliserTranslator(
- context);
- parent.visit(translator);
- translator.visitPath(parent, parent.getChildrenCount());
-
- String id = translator.idPath;
- if (id != null) {
-
- ClassDescriptor descriptor = context.getEntityDescriptor(id);
- if (descriptor == null) {
- throw new EJBQLException("Unmapped id variable: " + id);
- }
- String pathChunk = translator.lastPathComponent;
-
- Property property = descriptor.getProperty(pathChunk);
- if (property instanceof AttributeProperty) {
- String atrType = ((AttributeProperty) property)
- .getAttribute()
- .getType();
-
- type = TypesMapping.getSqlNameByType(TypesMapping
- .getSqlTypeByJava(atrType));
- }
- }
+ String type = getParentExpressionSqlTypeName(expression);
context.popMarker();
if (type == null) {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java Fri Sep 24 19:32:22 2010
@@ -376,34 +376,16 @@ public class QualifierTranslator extends
}
private boolean tryAppendConst(String path, Expression parentNode) throws IOException {
-
- if (path.length() < 3) {
- return false;
- }
-
- int lastDot = path.lastIndexOf('.');
- if (lastDot <= 0 || lastDot == path.length() - 1) {
- return false;
- }
-
- String constName = path.substring(lastDot + 1);
- String className = path.substring(0, lastDot);
-
Object constValue;
try {
- Class<?> klass = Util.getJavaClass(className);
- Field constField = klass.getField(constName);
- constValue = constField.get(null);
- }
- catch (ClassNotFoundException e) {
- return false;
- }
- catch (NoSuchFieldException e) {
- return false;
+ constValue = Util.getClassFieldValue(path);
}
catch (IllegalAccessException e) {
throw new ExpressionException("Can't access const field", e);
}
+ if (constValue == null) {
+ return false;
+ }
appendLiteral(constValue, paramsDbType(parentNode), parentNode);
return true;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java Fri Sep 24 19:32:22 2010
@@ -299,6 +299,10 @@ public class EJBQLBaseVisitor implements
return continueFlag;
}
+ public boolean visitConst(EJBQLExpression expression) {
+ return continueFlag;
+ }
+
public boolean visitPatternValue(EJBQLExpression expression) {
return continueFlag;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java Fri Sep 24 19:32:22 2010
@@ -275,7 +275,12 @@ public interface EJBQLExpressionVisitor
* visited.
*/
boolean visitPath(EJBQLExpression expression, int finishedChildIndex);
-
+
+ /**
+ * @since 3.1
+ */
+ boolean visitConst(EJBQLExpression expression);
+
boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex);
boolean visitPatternValue(EJBQLExpression expression);
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java Fri Sep 24 19:32:22 2010
@@ -47,6 +47,7 @@ import org.apache.cayenne.reflect.Proper
import org.apache.cayenne.reflect.PropertyVisitor;
import org.apache.cayenne.reflect.ToManyProperty;
import org.apache.cayenne.reflect.ToOneProperty;
+import org.apache.cayenne.util.Util;
/**
* Produces an {@link EJBQLCompiledExpression} out of an EJBQL expression tree.
@@ -66,6 +67,7 @@ class Compiler {
private Collection<EJBQLPath> paths;
private EJBQLExpressionVisitor fromItemVisitor;
private EJBQLExpressionVisitor joinVisitor;
+ private EJBQLExpressionVisitor constTransformVisitor;
private EJBQLExpressionVisitor pathVisitor;
private EJBQLExpressionVisitor rootDescriptorVisitor;
private List<Object> resultComponents;
@@ -80,6 +82,7 @@ class Compiler {
this.fromItemVisitor = new FromItemVisitor();
this.joinVisitor = new JoinVisitor();
this.pathVisitor = new PathVisitor();
+ this.constTransformVisitor = new ConstTransformVisitor();
}
CompiledExpression compile(String source, EJBQLExpression parsed) {
@@ -441,6 +444,7 @@ class Compiler {
@Override
public boolean visitWhere(EJBQLExpression expression) {
+ expression.visit(constTransformVisitor);
expression.visit(pathVisitor);
// continue with children as there may be subselects with their own id
@@ -583,6 +587,37 @@ class Compiler {
}
}
+ class ConstTransformVisitor extends EJBQLBaseVisitor {
+
+ @Override
+ public boolean visitPath(EJBQLExpression expression, int finishedChildIndex) {
+ EJBQLPath pathExpression = (EJBQLPath) expression;
+ String path = pathExpression.getAbsolutePath();
+ Object constValue;
+ try {
+ constValue = Util.getClassFieldValue(path);
+ }
+ catch (IllegalAccessException e) {
+ throw new EJBQLException("Can't access const field", e);
+ }
+ if (constValue != null) {
+ transformNode(pathExpression, path, constValue);
+ }
+ return false;
+ }
+
+ private void transformNode(
+ EJBQLPath pathExpression,
+ String path,
+ Object constValue) {
+ EJBQLConstant constantExpression = new EJBQLConstant(
+ pathExpression,
+ path,
+ constValue);
+ pathExpression.getParent().replaceChild(pathExpression, constantExpression);
+ }
+ }
+
class PathVisitor extends EJBQLBaseVisitor {
@Override
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLConstant.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLConstant.java?rev=1001040&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLConstant.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLConstant.java Fri Sep 24 19:32:22 2010
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.ejbql.parser;
+
+import org.apache.cayenne.ejbql.EJBQLExpressionVisitor;
+
+public class EJBQLConstant extends SimpleNode {
+
+ private String path;
+ private Object value;
+
+ public EJBQLConstant(EJBQLPath pathExpression, String path, Object value) {
+ super(pathExpression.id);
+ this.parent = pathExpression.parent;
+ this.path = path;
+ this.value = value;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ protected boolean visitNode(EJBQLExpressionVisitor visitor) {
+ return visitor.visitConst(this);
+ }
+}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java Fri Sep 24 19:32:22 2010
@@ -92,6 +92,18 @@ public abstract class SimpleNode impleme
return jjtGetNumChildren();
}
+ public void replaceChild(SimpleNode oldChild, SimpleNode newChild) {
+ for (int i = 0; i < children.length; i++) {
+ if (children[i] == oldChild) {
+ children[i] = newChild;
+ }
+ }
+ }
+
+ public SimpleNode getParent() {
+ return parent;
+ }
+
public String getName() {
String className = getClass().getName();
int i = className.lastIndexOf("EJBQL");
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/Util.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/Util.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/Util.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/Util.java Fri Sep 24 19:32:22 2010
@@ -34,6 +34,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
+import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.net.URI;
@@ -739,6 +740,38 @@ public class Util {
}
}
+ /**
+ * Returns constant field value by fully qualified path.
+ *
+ * @return Field value or {@code null} if class or field specified in path was not
+ * found.
+ * @since 3.1
+ */
+ public static Object getClassFieldValue(String path) throws IllegalAccessException {
+ if (path.length() < 3) {
+ return null;
+ }
+
+ int lastDot = path.lastIndexOf('.');
+ if (lastDot <= 0 || lastDot == path.length() - 1) {
+ return null;
+ }
+
+ String constName = path.substring(lastDot + 1);
+ String className = path.substring(0, lastDot);
+ try {
+ Class<?> klass = getJavaClass(className);
+ Field constField = klass.getField(constName);
+ return constField.get(null);
+ }
+ catch (ClassNotFoundException e) {
+ return null;
+ }
+ catch (NoSuchFieldException e) {
+ return null;
+ }
+ }
+
static void setReverse(
final Persistent sourceObject,
String propertyName,
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/ConstQueryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/ConstQueryTest.java?rev=1001040&r1=1001039&r2=1001040&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/ConstQueryTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/ConstQueryTest.java Fri Sep 24 19:32:22 2010
@@ -103,4 +103,25 @@ public class ConstQueryTest extends Serv
assertEquals(1, users.size());
assertEquals("org.apache.cayenne.testdo.consttest.Const1Type.ADMIN", ((Const1Entity) users.get(0)).getName());
}
+
+ public void testSelectByEnumValueWithEJBQL() throws Exception {
+ createConst1EntityDataSet();
+
+ EJBQLQuery query = new EJBQLQuery(
+ "SELECT e FROM Const1Entity e WHERE e.type = :t");
+ query.setParameter("t", Const1Type.ORDINARY);
+ List entities = context.performQuery(query);
+ assertEquals(1, entities.size());
+ assertEquals("entity1", ((Const1Entity) entities.get(0)).getName());
+ }
+
+ public void testSelectByEnumValueSpecifiedAsConstantWithEJBQL() throws Exception {
+ createConst1EntityDataSet();
+
+ EJBQLQuery query = new EJBQLQuery(
+ "SELECT e FROM Const1Entity e WHERE e.type = org.apache.cayenne.testdo.consttest.Const1Type.ORDINARY");
+ List entities = context.performQuery(query);
+ assertEquals(1, entities.size());
+ assertEquals("entity1", ((Const1Entity) entities.get(0)).getName());
+ }
}