You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/01/24 08:41:39 UTC

cayenne git commit: CAY-2397 Modeler: Unable to set enum:value as Entity qualifier

Repository: cayenne
Updated Branches:
  refs/heads/master c0e9d0ad6 -> f5321be3f


CAY-2397 Modeler: Unable to set enum:value as Entity qualifier


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/f5321be3
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/f5321be3
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/f5321be3

Branch: refs/heads/master
Commit: f5321be3fb4192ddcf3a2e5dcf05d0c703a5e01a
Parents: c0e9d0a
Author: Nikita Timofeev <st...@gmail.com>
Authored: Wed Jan 24 11:35:10 2018 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Wed Jan 24 11:35:10 2018 +0300

----------------------------------------------------------------------
 RELEASE-NOTES.txt                               |   1 +
 .../configuration/xml/ObjEntityHandler.java     |  11 +-
 .../org/apache/cayenne/exp/parser/ASTEnum.java  | 142 +++++++++++++++++++
 .../cayenne/exp/parser/ExpressionParser.java    |   4 +-
 .../parser/ExpressionParserTreeConstants.java   |   4 +-
 .../apache/cayenne/exp/parser/ParserUtil.java   |  58 --------
 .../cayenne/exp/parser/ExpressionParser.jjt     |   2 +-
 .../java/org/apache/cayenne/access/EnumIT.java  |  10 ++
 .../cayenne/exp/ExpressionFactoryTest.java      |  88 +++++++-----
 .../org/apache/cayenne/exp/ExpressionTest.java  |  52 +++----
 .../cayenne/testdo/enum_test/EnumEntity2.java   |   9 ++
 .../testdo/enum_test/auto/_EnumEntity2.java     |  87 ++++++++++++
 .../src/test/resources/cayenne-enum.xml         |   2 +
 cayenne-server/src/test/resources/enum.map.xml  |   9 +-
 .../modeler/util/ExpressionConvertor.java       |   3 +-
 15 files changed, 358 insertions(+), 124 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 5b61a78..4f15920 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -31,6 +31,7 @@ CAY-2387 Can't select byte[] property with ColumnSelect
 CAY-2388 Modeler: Visualization issues with undo/redo actions for attributes and relationships
 CAY-2389 DbEntity qualifier with DbPath expression translates into wrong SQL
 CAY-2392 Modeler: Unable to remove DataNode
+CAY-2397 Modeler: Unable to set enum:value as Entity qualifier
 
 ----------------------------------
 Release: 4.1.M1

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java
index e9ee9aa..456b9d6 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/ObjEntityHandler.java
@@ -19,11 +19,14 @@
 
 package org.apache.cayenne.configuration.xml;
 
+import org.apache.cayenne.exp.ExpressionException;
 import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.map.CallbackDescriptor;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
@@ -33,6 +36,8 @@ import org.xml.sax.SAXException;
  */
 public class ObjEntityHandler extends NamespaceAwareNestedTagHandler {
 
+    private static Logger logger = LoggerFactory.getLogger(ObjEntityHandler.class);
+
     private static final String OBJ_ENTITY_TAG = "obj-entity";
     private static final String OBJ_ATTRIBUTE_TAG = "obj-attribute";
     private static final String OBJ_ATTRIBUTE_OVERRIDE_TAG = "attribute-override";
@@ -196,7 +201,11 @@ public class ObjEntityHandler extends NamespaceAwareNestedTagHandler {
         }
 
         if (entity != null) {
-            entity.setDeclaredQualifier(ExpressionFactory.exp(qualifier));
+            try {
+                entity.setDeclaredQualifier(ExpressionFactory.exp(qualifier));
+            } catch (ExpressionException ex) {
+                logger.warn("Unable to parse entity " + entity.getName() + " qualifier", ex);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEnum.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEnum.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEnum.java
new file mode 100644
index 0000000..8f7e48a
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEnum.java
@@ -0,0 +1,142 @@
+/*****************************************************************
+ *   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.exp.parser;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.Util;
+
+/**
+ * Scalar node that represents constant enumeration value.
+ * It resolves actual value at a late stage to be parsable in environment where
+ * final Enum class is not known, i.e. in Modeler.
+ *
+ * @since 4.1
+ */
+public class ASTEnum extends ASTScalar {
+
+    ASTEnum(int id) {
+        super(id);
+    }
+
+    public ASTEnum() {
+        super(ExpressionParserTreeConstants.JJTENUM);
+    }
+
+    public ASTEnum(Object value) {
+        super(ExpressionParserTreeConstants.JJTENUM);
+        setValue(value);
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) {
+        return getValueAsEnum().resolve();
+    }
+
+    @Override
+    public Expression shallowCopy() {
+        ASTScalar copy = new ASTEnum(id);
+        copy.value = value;
+        return copy;
+    }
+
+    @Override
+    public void appendAsEJBQL(List<Object> parameterAccumulator, Appendable out, String rootId) throws IOException {
+        Object scalar = getValueAsEnum().resolve();
+        SimpleNode.encodeScalarAsEJBQL(parameterAccumulator, out, scalar);
+    }
+
+    @Override
+    public Object getValue() {
+        return getValueAsEnum().resolve();
+    }
+
+    public void setEnumValue(String enumPath) throws ParseException{
+        if (enumPath == null) {
+            throw new ParseException("Null 'enumPath'");
+        }
+
+        int dot = enumPath.lastIndexOf('.');
+        if (dot <= 0 || dot == enumPath.length() - 1) {
+            throw new ParseException("Invalid enum path: " + enumPath);
+        }
+
+        String className = enumPath.substring(0, dot);
+        String enumName = enumPath.substring(dot + 1);
+
+        setValue(new ASTEnum.EnumValue(className, enumName));
+    }
+
+    EnumValue getValueAsEnum() {
+        return (EnumValue)value;
+    }
+
+    static final class EnumValue {
+        String className;
+        String enumName;
+
+        EnumValue(String className, String enumName) {
+            this.className = Objects.requireNonNull(className);
+            this.enumName = Objects.requireNonNull(enumName);
+        }
+
+        Enum<?> resolve() {
+            Class enumClass;
+            try {
+                enumClass = Util.getJavaClass(className);
+            } catch (ClassNotFoundException e) {
+                throw new CayenneRuntimeException("Enum class not found: " + className);
+            }
+            if (!enumClass.isEnum()) {
+                throw new CayenneRuntimeException("Specified class is not an enum: " + className);
+            }
+            try {
+                return Enum.valueOf(enumClass, enumName);
+            } catch (IllegalArgumentException e) {
+                throw new CayenneRuntimeException("Invalid enum path: " + className + "." + enumName);
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || EnumValue.class != o.getClass()) return false;
+
+            EnumValue enumValue = (EnumValue) o;
+            return className.equals(enumValue.className) && enumName.equals(enumValue.enumName);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = className.hashCode();
+            result = 31 * result + enumName.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "enum:" + className + "." + enumName;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
index ff0fde8..06d4c0d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
@@ -2511,13 +2511,13 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case 67:
       jj_consume_token(67);
       t = jj_consume_token(PROPERTY_PATH);
-                                   ASTScalar jjtn004 = new ASTScalar(JJTSCALAR);
+                                   ASTEnum jjtn004 = new ASTEnum(JJTENUM);
                                    boolean jjtc004 = true;
                                    jjtree.openNodeScope(jjtn004);
       try {
                                    jjtree.closeNodeScope(jjtn004,  0);
                                    jjtc004 = false;
-                                   jjtn004.setValue(ParserUtil.makeEnum(t.image));
+                                   jjtn004.setEnumValue(t.image);
       } finally {
                                    if (jjtc004) {
                                      jjtree.closeNodeScope(jjtn004,  0);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
index 2b8c022..15d5de3 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
@@ -78,6 +78,7 @@ public interface ExpressionParserTreeConstants
   public int JJTNAMEDPARAMETER = 53;
   public int JJTOBJPATH = 54;
   public int JJTDBPATH = 55;
+  public int JJTENUM = 56;
 
 
   public String[] jjtNodeName = {
@@ -137,6 +138,7 @@ public interface ExpressionParserTreeConstants
     "NamedParameter",
     "ObjPath",
     "DbPath",
+    "Enum",
   };
 }
-/* JavaCC - OriginalChecksum=fa5ebea216f594b98b337cf22871715e (do not edit this line) */
+/* JavaCC - OriginalChecksum=6976e9a526d76d12c8693beadbe8a363 (do not edit this line) */

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParserUtil.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParserUtil.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParserUtil.java
deleted file mode 100644
index a243c1f..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ParserUtil.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*****************************************************************
- *   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.exp.parser;
-
-import org.apache.cayenne.util.Util;
-
-class ParserUtil {
-
-    static Object makeEnum(String enumPath) throws ParseException {
-
-        if (enumPath == null) {
-            throw new ParseException("Null 'enumPath'");
-        }
-
-        int dot = enumPath.lastIndexOf('.');
-        if (dot <= 0 || dot == enumPath.length() - 1) {
-            throw new ParseException("Invalid enum path: " + enumPath);
-        }
-
-        String className = enumPath.substring(0, dot);
-        String enumName = enumPath.substring(dot + 1);
-
-        Class enumClass;
-        try {
-            enumClass = Util.getJavaClass(className);
-        }
-        catch (ClassNotFoundException e) {
-            throw new ParseException("Enum class not found: " + className);
-        }
-
-        if (!enumClass.isEnum()) {
-            throw new ParseException("Specified class is not an enum: " + className);
-        }
-
-        try {
-            return Enum.valueOf(enumClass, enumName);
-        }
-        catch (IllegalArgumentException e) {
-            throw new ParseException("Invalid enum path: " + enumPath);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
index 2bca76d..006f241 100644
--- a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
+++ b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
@@ -579,7 +579,7 @@ void pathExpression() : {
    |
      "db:"   t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #DbPath(0)
    |
-     "enum:" t = <PROPERTY_PATH> { jjtThis.setValue(ParserUtil.makeEnum(t.image)); } #Scalar(0)
+     "enum:" t = <PROPERTY_PATH> { jjtThis.setEnumValue(t.image); } #Enum(0)
    )
 }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/java/org/apache/cayenne/access/EnumIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/EnumIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/EnumIT.java
index 035fc3a..094a4d8 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/EnumIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/EnumIT.java
@@ -28,11 +28,13 @@ import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.enum_test.Enum1;
 import org.apache.cayenne.testdo.enum_test.EnumEntity;
+import org.apache.cayenne.testdo.enum_test.EnumEntity2;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertSame;
 
@@ -85,4 +87,12 @@ public class EnumIT extends ServerCase {
         assertNotNull(e);
         assertSame(Enum1.one, e.getEnumAttribute());
     }
+
+    @Test
+    public void createObjectWithEnumQualifier() {
+        EnumEntity2 test = context.newObject(EnumEntity2.class);
+        context.commitChanges();
+
+        assertEquals(Enum1.two, test.getEnumAttribute());
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
index a41344c..60a44d9 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
@@ -42,19 +42,19 @@ public class ExpressionFactoryTest {
 	private TstTraversalHandler handler;
 
 	@Before
-	public void before() throws Exception {
+	public void before() {
 		handler = new TstTraversalHandler();
 	}
 
 	@Test(expected = ExpressionException.class)
-	public void testExpressionOfBadType() throws Exception {
+	public void testExpressionOfBadType() {
 		// non existing type
 		int badType = -50;
 		ExpressionFactory.expressionOfType(badType);
 	}
 
 	@Test
-	public void testBetweenExp() throws Exception {
+	public void testBetweenExp() {
 		Object v1 = new Object();
 		Object v2 = new Object();
 		Expression exp = ExpressionFactory.betweenExp("abc", v1, v2);
@@ -65,7 +65,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testBetweenDbExp() throws Exception {
+	public void testBetweenDbExp() {
 		Object v1 = new Object();
 		Object v2 = new Object();
 		Expression exp = ExpressionFactory.betweenDbExp("abc", v1, v2);
@@ -76,7 +76,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testNotBetweenExp() throws Exception {
+	public void testNotBetweenExp() {
 		Object v1 = new Object();
 		Object v2 = new Object();
 		Expression exp = ExpressionFactory.notBetweenExp("abc", v1, v2);
@@ -87,7 +87,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testNotBetweenDbExp() throws Exception {
+	public void testNotBetweenDbExp() {
 		Object v1 = new Object();
 		Object v2 = new Object();
 		Expression exp = ExpressionFactory.notBetweenDbExp("abc", v1, v2);
@@ -98,14 +98,14 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testGreaterExp() throws Exception {
+	public void testGreaterExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.greaterExp("abc", v);
 		assertEquals(Expression.GREATER_THAN, exp.getType());
 	}
 
 	@Test
-	public void testGreaterDbExp() throws Exception {
+	public void testGreaterDbExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.greaterDbExp("abc", v);
 		assertEquals(Expression.GREATER_THAN, exp.getType());
@@ -115,14 +115,14 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testGreaterOrEqualExp() throws Exception {
+	public void testGreaterOrEqualExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.greaterOrEqualExp("abc", v);
 		assertEquals(Expression.GREATER_THAN_EQUAL_TO, exp.getType());
 	}
 
 	@Test
-	public void testGreaterOrEqualDbExp() throws Exception {
+	public void testGreaterOrEqualDbExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.greaterOrEqualDbExp("abc", v);
 		assertEquals(Expression.GREATER_THAN_EQUAL_TO, exp.getType());
@@ -132,14 +132,14 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLessExp() throws Exception {
+	public void testLessExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.lessExp("abc", v);
 		assertEquals(Expression.LESS_THAN, exp.getType());
 	}
 
 	@Test
-	public void testLessDbExp() throws Exception {
+	public void testLessDbExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.lessDbExp("abc", v);
 		assertEquals(Expression.LESS_THAN, exp.getType());
@@ -149,7 +149,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLessOrEqualExp() throws Exception {
+	public void testLessOrEqualExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.lessOrEqualExp("abc", v);
 		assertEquals(Expression.LESS_THAN_EQUAL_TO, exp.getType());
@@ -159,7 +159,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLessOrEqualDbExp() throws Exception {
+	public void testLessOrEqualDbExp() {
 		Object v = new Object();
 		Expression exp = ExpressionFactory.lessOrEqualDbExp("abc", v);
 		assertEquals(Expression.LESS_THAN_EQUAL_TO, exp.getType());
@@ -169,13 +169,13 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testInExp1() throws Exception {
+	public void testInExp1() {
 		Expression exp = ExpressionFactory.inExp("abc", "a", "b");
 		assertEquals(Expression.IN, exp.getType());
 	}
 
 	@Test
-	public void testInExp2() throws Exception {
+	public void testInExp2() {
 		List<Object> v = new ArrayList<>();
 		v.add("a");
 		v.add("b");
@@ -184,20 +184,20 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testInExp3() throws Exception {
+	public void testInExp3() {
 		List<Object> v = new ArrayList<>();
 		Expression exp = ExpressionFactory.inExp("abc", v);
 		assertEquals(Expression.FALSE, exp.getType());
 	}
 
 	@Test
-	public void testNotInExp1() throws Exception {
+	public void testNotInExp1() {
 		Expression exp = ExpressionFactory.notInExp("abc", "a", "b");
 		assertEquals(Expression.NOT_IN, exp.getType());
 	}
 
 	@Test
-	public void testNotInExp2() throws Exception {
+	public void testNotInExp2() {
 		List<Object> v = new ArrayList<>();
 		v.add("a");
 		v.add("b");
@@ -206,14 +206,14 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testNotInExp3() throws Exception {
+	public void testNotInExp3() {
 		List<Object> v = new ArrayList<>();
 		Expression exp = ExpressionFactory.notInExp("abc", v);
 		assertEquals(Expression.TRUE, exp.getType());
 	}
 
 	@Test
-	public void testLikeExp() throws Exception {
+	public void testLikeExp() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeExp("abc", v);
 		assertEquals(Expression.LIKE, exp.getType());
@@ -223,7 +223,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLikeDbExp() throws Exception {
+	public void testLikeDbExp() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeDbExp("abc", v);
 		assertEquals(Expression.LIKE, exp.getType());
@@ -233,7 +233,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLikeExpEscape() throws Exception {
+	public void testLikeExpEscape() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeExp("=abc", v, '=');
 		assertEquals(Expression.LIKE, exp.getType());
@@ -245,7 +245,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLikeIgnoreCaseExp() throws Exception {
+	public void testLikeIgnoreCaseExp() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeIgnoreCaseExp("abc", v);
 		assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType());
@@ -256,7 +256,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLikeIgnoreCaseExpEscape() throws Exception {
+	public void testLikeIgnoreCaseExpEscape() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeIgnoreCaseExp("=abc", v, '=');
 		assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType());
@@ -267,7 +267,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testLikeIgnoreCaseDbExp() throws Exception {
+	public void testLikeIgnoreCaseDbExp() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.likeIgnoreCaseDbExp("abc", v);
 		assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType());
@@ -277,7 +277,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testNotLikeIgnoreCaseExp() throws Exception {
+	public void testNotLikeIgnoreCaseExp() {
 		String v = "abc";
 		Expression exp = ExpressionFactory.notLikeIgnoreCaseExp("abc", v);
 		assertEquals(Expression.NOT_LIKE_IGNORE_CASE, exp.getType());
@@ -285,7 +285,7 @@ public class ExpressionFactoryTest {
 
 	// testing CAY-941 bug
 	@Test
-	public void testLikeExpNull() throws Exception {
+	public void testLikeExpNull() {
 		Expression exp = ExpressionFactory.likeExp("abc", null);
 		assertEquals(Expression.LIKE, exp.getType());
 
@@ -295,7 +295,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testMatchAllExp() throws Exception {
+	public void testMatchAllExp() {
 		// create expressions and check the counts,
 		// leaf count should be (2N) : 2 leafs for each pair
 		// node count should be (2N + 1) for nodes with more than 1 pair
@@ -323,7 +323,7 @@ public class ExpressionFactoryTest {
 	}
 
 	@Test
-	public void testJoinExp() throws Exception {
+	public void testJoinExp() {
 		// create expressions and check the counts,
 		// leaf count should be (2N) : 2 leafs for each expression
 		// node count should be N > 1 ? 2 * N + 1 : 2 * N
@@ -374,7 +374,7 @@ public class ExpressionFactoryTest {
 	@Test
 	public void testAnd_Collection_Empty() {
 
-		Expression e = ExpressionFactory.and(Collections.<Expression> emptyList());
+		Expression e = ExpressionFactory.and(Collections.emptyList());
 
 		// hmm... is this really a valid return value?
 		assertNull(e);
@@ -469,9 +469,21 @@ public class ExpressionFactoryTest {
 		assertEquals(ExpEnum1.THREE, e3.getOperand(1));
 	}
 
+	@Test
+	public void testExp_EnumValid1() {
+		Bean a = new Bean();
+		a.setA(ExpEnum1.TWO);
+		Expression exp = ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.TWO");
+		Object result = exp.evaluate(a);
+		assertEquals(Boolean.TRUE, result);
+	}
+
 	@Test(expected = ExpressionException.class)
 	public void testExp_EnumInvalid1() {
-		ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.BOGUS");
+		Bean a = new Bean();
+		a.setA(ExpEnum1.TWO);
+		Expression exp = ExpressionFactory.exp("a = enum:org.apache.cayenne.exp.ExpEnum1.BOGUS");
+		exp.evaluate(a);
 	}
 
 	@Test(expected = ExpressionException.class)
@@ -506,4 +518,16 @@ public class ExpressionFactoryTest {
     public void testExceptionInParse() {
         ExpressionFactory.exp("name like %32_65415'");
     }
+
+	public static class Bean {
+		public ExpEnum1 a;
+
+		public ExpEnum1 getA() {
+			return a;
+		}
+
+		public void setA(ExpEnum1 a) {
+			this.a = a;
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
index e0e306b..cf56194 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionTest.java
@@ -33,26 +33,26 @@ import org.junit.Test;
 public class ExpressionTest {
 
 	@Test
-	public void testToEJBQL_numericType_integer() throws IOException {
-		Expression e = ExpressionFactory.matchExp("consignment.parts", new Integer(123));
+	public void testToEJBQL_numericType_integer() {
+		Expression e = ExpressionFactory.matchExp("consignment.parts", 123);
 		assertEquals("x.consignment.parts = 123", e.toEJBQL("x"));
 	}
 
 	@Test
-	public void testToEJBQL_numericType_long() throws IOException {
-		Expression e = ExpressionFactory.matchExp("consignment.parts", new Long(1418342400));
+	public void testToEJBQL_numericType_long() {
+		Expression e = ExpressionFactory.matchExp("consignment.parts", 1418342400L);
 		assertEquals("x.consignment.parts = 1418342400", e.toEJBQL("x"));
 	}
 
 	@Test
-	public void testToEJBQL_numericType_float() throws IOException {
-		Expression e = ExpressionFactory.greaterOrEqualExp("consignment.parts", new Float("3.145"));
+	public void testToEJBQL_numericType_float() {
+		Expression e = ExpressionFactory.greaterOrEqualExp("consignment.parts", Float.valueOf("3.145"));
 		assertEquals("x.consignment.parts >= 3.145", e.toEJBQL("x"));
 	}
 
 	@Test
-	public void testToEJBQL_numericType_double() throws IOException {
-		Expression e = ExpressionFactory.greaterOrEqualExp("consignment.parts", new Double(3.14));
+	public void testToEJBQL_numericType_double()  {
+		Expression e = ExpressionFactory.greaterOrEqualExp("consignment.parts", 3.14);
 		assertEquals("x.consignment.parts >= 3.14", e.toEJBQL("x"));
 	}
 
@@ -63,7 +63,7 @@ public class ExpressionTest {
 		Expression e = ExpressionFactory.greaterOrEqualExp("dateOfBirth", now);
 
 		StringBuilder buffer = new StringBuilder();
-		List<Object> parametersAccumulator = new ArrayList<Object>();
+		List<Object> parametersAccumulator = new ArrayList<>();
 
 		e.appendAsEJBQL(parametersAccumulator, buffer, "x");
 
@@ -81,7 +81,7 @@ public class ExpressionTest {
 		Expression e = ExpressionFactory.inExp("artistName", "a", "b", "c");
 
 		StringBuilder buffer = new StringBuilder();
-		List<Object> parametersAccumulator = new ArrayList<Object>();
+		List<Object> parametersAccumulator = new ArrayList<>();
 
 		e.appendAsEJBQL(parametersAccumulator, buffer, "x");
 
@@ -196,7 +196,7 @@ public class ExpressionTest {
 
 		assertEquals(Expression.BITWISE_NOT, exp.getType());
 		assertEquals(1, ((SimpleNode) exp).jjtGetNumChildren());
-		assertEquals(new Long(-8), exp.evaluate(new Object())); // ~7 = -8 in
+		assertEquals(-8L, exp.evaluate(new Object())); // ~7 = -8 in
 																// digital world
 	}
 
@@ -206,7 +206,7 @@ public class ExpressionTest {
 
 		assertEquals(Expression.BITWISE_AND, exp.getType());
 		assertEquals(2, ((SimpleNode) exp).jjtGetNumChildren());
-		assertEquals(new Long(0), exp.evaluate(new Object()));
+		assertEquals(0L, exp.evaluate(new Object()));
 	}
 
 	@Test
@@ -215,7 +215,7 @@ public class ExpressionTest {
 
 		assertEquals(Expression.BITWISE_OR, exp.getType());
 		assertEquals(2, ((SimpleNode) exp).jjtGetNumChildren());
-		assertEquals(new Long(1), exp.evaluate(new Object()));
+		assertEquals(1L, exp.evaluate(new Object()));
 	}
 
 	@Test
@@ -224,7 +224,7 @@ public class ExpressionTest {
 
 		assertEquals(Expression.BITWISE_XOR, exp.getType());
 		assertEquals(2, ((SimpleNode) exp).jjtGetNumChildren());
-		assertEquals(new Long(1), exp.evaluate(new Object()));
+		assertEquals(1L, exp.evaluate(new Object()));
 	}
 
 	@Test
@@ -233,7 +233,7 @@ public class ExpressionTest {
 
 		assertEquals(Expression.BITWISE_LEFT_SHIFT, exp.getType());
 		assertEquals(2, ((SimpleNode) exp).jjtGetNumChildren());
-		assertEquals(new Long(28), exp.evaluate(new Object()));
+		assertEquals(28L, exp.evaluate(new Object()));
 	}
 
 	@Test
@@ -243,7 +243,7 @@ public class ExpressionTest {
 		assertEquals(Expression.BITWISE_RIGHT_SHIFT, exp.getType());
 		assertEquals(2, ((SimpleNode) exp).jjtGetNumChildren());
 
-		assertEquals(new Long(1), exp.evaluate(new Object()));
+		assertEquals(1L, exp.evaluate(new Object()));
 	}
 
 	/**
@@ -302,7 +302,7 @@ public class ExpressionTest {
 		Expression e1 = ExpressionFactory.exp("5555 | ~5555");
 		Expression e2 = ExpressionFactory.exp("9999 & ~9999");
 
-		assertEquals(new Long(-1), e1.evaluate(new Object())); // ~0 = -1 that
+		assertEquals(-1L, e1.evaluate(new Object())); // ~0 = -1 that
 																// is the way
 																// how
 																// robots kill
@@ -316,7 +316,7 @@ public class ExpressionTest {
 																// bitwise
 																// operations
 																// logics
-		assertEquals(new Long(0), e2.evaluate(new Object()));
+		assertEquals(0L, e2.evaluate(new Object()));
 	}
 
 	/**
@@ -328,7 +328,7 @@ public class ExpressionTest {
 	public void testBitwiseHuntingtonEquation() {
 		Expression theHuntingEquation = ExpressionFactory.exp("~(~3748 | 4095) | ~(~3748 | ~4095)");
 
-		assertEquals(new Long(3748), theHuntingEquation.evaluate(new Object()));
+		assertEquals(3748L, theHuntingEquation.evaluate(new Object()));
 	}
 
 	/**
@@ -341,7 +341,7 @@ public class ExpressionTest {
 	public void testBitwiseRobbinsEquation() {
 		Expression theRobbinsEquation = ExpressionFactory.exp("~(~(5111 | 4095) | ~(5111 | ~4095))");
 
-		assertEquals(new Long(5111), theRobbinsEquation.evaluate(new Object()));
+		assertEquals(5111L, theRobbinsEquation.evaluate(new Object()));
 	}
 
 	/**
@@ -374,11 +374,11 @@ public class ExpressionTest {
 		Expression e5 = ExpressionFactory.exp("6 / 2 & 3"); // (6 / 2) & 3 = 3 &
 															// 3 = 3
 
-		assertEquals(new Long(2), e1.evaluate(new Object()));
-		assertEquals(new Long(0), e2.evaluate(new Object()));
-		assertEquals(new Long(7), e3.evaluate(new Object()));
-		assertEquals(new Long(6), e4.evaluate(new Object()));
-		assertEquals(new Long(3), e5.evaluate(new Object()));
+		assertEquals(2L, e1.evaluate(new Object()));
+		assertEquals(0L, e2.evaluate(new Object()));
+		assertEquals(7L, e3.evaluate(new Object()));
+		assertEquals(6L, e4.evaluate(new Object()));
+		assertEquals(3L, e5.evaluate(new Object()));
 	}
 
 	@Test
@@ -386,7 +386,7 @@ public class ExpressionTest {
 		Expression e = ExpressionFactory.exp("artistName != 'bla'");
 
 		StringBuilder buffer = new StringBuilder();
-		List<Object> parametersAccumulator = new ArrayList<Object>();
+		List<Object> parametersAccumulator = new ArrayList<>();
 		e.appendAsEJBQL(parametersAccumulator, buffer, "x");
 		String ejbql = buffer.toString();
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/EnumEntity2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/EnumEntity2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/EnumEntity2.java
new file mode 100644
index 0000000..b9c7839
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/EnumEntity2.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.enum_test;
+
+import org.apache.cayenne.testdo.enum_test.auto._EnumEntity2;
+
+public class EnumEntity2 extends _EnumEntity2 {
+
+    private static final long serialVersionUID = 1L; 
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/auto/_EnumEntity2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/auto/_EnumEntity2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/auto/_EnumEntity2.java
new file mode 100644
index 0000000..6223e53
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/enum_test/auto/_EnumEntity2.java
@@ -0,0 +1,87 @@
+package org.apache.cayenne.testdo.enum_test.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.enum_test.Enum1;
+
+/**
+ * Class _EnumEntity2 was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _EnumEntity2 extends BaseDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final Property<Enum1> ENUM_ATTRIBUTE = Property.create("enumAttribute", Enum1.class);
+
+    protected Enum1 enumAttribute;
+
+
+    public void setEnumAttribute(Enum1 enumAttribute) {
+        beforePropertyWrite("enumAttribute", this.enumAttribute, enumAttribute);
+        this.enumAttribute = enumAttribute;
+    }
+
+    public Enum1 getEnumAttribute() {
+        beforePropertyRead("enumAttribute");
+        return this.enumAttribute;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "enumAttribute":
+                return this.enumAttribute;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "enumAttribute":
+                this.enumAttribute = (Enum1)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.enumAttribute);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.enumAttribute = (Enum1)in.readObject();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/resources/cayenne-enum.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/cayenne-enum.xml b/cayenne-server/src/test/resources/cayenne-enum.xml
index 84bdc40..de50894 100644
--- a/cayenne-server/src/test/resources/cayenne-enum.xml
+++ b/cayenne-server/src/test/resources/cayenne-enum.xml
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <domain xmlns="http://cayenne.apache.org/schema/10/domain"
+	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain http://cayenne.apache.org/schema/10/domain.xsd"
 	 project-version="10">
 	<map name="enum"/>
 </domain>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/cayenne-server/src/test/resources/enum.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/enum.map.xml b/cayenne-server/src/test/resources/enum.map.xml
index 30019c9..56b340b 100644
--- a/cayenne-server/src/test/resources/enum.map.xml
+++ b/cayenne-server/src/test/resources/enum.map.xml
@@ -4,7 +4,6 @@
 	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap http://cayenne.apache.org/schema/10/modelMap.xsd"
 	 project-version="10">
 	<property name="defaultPackage" value="org.apache.cayenne.testdo.enum_test"/>
-	<property name="defaultSuperclass" value="org.apache.cayenne.CayenneDataObject"/>
 	<property name="clientSupported" value="true"/>
 	<property name="defaultClientPackage" value="test.client"/>
 	<property name="defaultClientSuperclass" value="org.apache.cayenne.PersistentObject"/>
@@ -12,7 +11,15 @@
 		<db-attribute name="ENUM_ATTRIBUTE" type="VARCHAR" length="250"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="ENUM_ENTITY_2">
+		<db-attribute name="ENUM_ATTRIBUTE" type="VARCHAR" length="250"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+	</db-entity>
 	<obj-entity name="EnumEntity" className="org.apache.cayenne.testdo.enum_test.EnumEntity" dbEntityName="ENUM_ENTITY">
 		<obj-attribute name="enumAttribute" type="org.apache.cayenne.testdo.enum_test.Enum1" db-attribute-path="ENUM_ATTRIBUTE"/>
 	</obj-entity>
+	<obj-entity name="EnumEntity2" className="org.apache.cayenne.testdo.enum_test.EnumEntity2" dbEntityName="ENUM_ENTITY_2">
+		<qualifier><![CDATA[enumAttribute = enum:org.apache.cayenne.testdo.enum_test.Enum1.two]]></qualifier>
+		<obj-attribute name="enumAttribute" type="org.apache.cayenne.testdo.enum_test.Enum1" db-attribute-path="ENUM_ATTRIBUTE"/>
+	</obj-entity>
 </data-map>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f5321be3/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ExpressionConvertor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ExpressionConvertor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ExpressionConvertor.java
index 277dba0..e004e5a 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ExpressionConvertor.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ExpressionConvertor.java
@@ -52,8 +52,7 @@ public class ExpressionConvertor {
 
         try {
             return ExpressionFactory.exp(string);
-        }
-        catch (ExpressionException eex) {
+        } catch (ExpressionException eex) {
             // this is likely a parse exception... show detailed message
             Throwable cause = Util.unwindException(eex);
             String message =