Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

changed inheritance type to use type if specified, class name if not;…

… added more test cases.
  • Loading branch information...
commit 3d595a7d4d0c931bd86e0ee787ff74e50ecfe96a 1 parent 7d22a81
Cory Hacking authored
View
4 grails-app/conf/couchdb/views/person/list.map.js → grails-app/conf/couchdb/views/human/list.map.js
@@ -1,8 +1,8 @@
function(doc) {
- if (doc.type.lastIndexOf('person', 0) === 0) {
+ if (doc.type.lastIndexOf('human', 0) === 0) {
- var subType = doc.type.substring(5);
+ var subType = doc.type.substring(4);
// just emit the name
emit(doc.name, {name:doc.name, subType: subType});
View
28 grails-app/domain/org/acme/NoType.groovy
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed 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.acme
+
+import grails.plugins.couchdb.CouchEntity
+
+/**
+ * Class with type explicitly disabled for testing.
+ *
+ * @author Cory Hacking
+ */
+@CouchEntity(type = "")
+class NoType {
+
+}
View
12 grails-app/domain/org/acme/Person.groovy
@@ -21,15 +21,15 @@ import grails.plugins.couchdb.CouchEntity
*
* @author Warner Onstine, Cory Hacking
*/
-@CouchEntity
+@CouchEntity(type = "human")
class Person {
- String name
- Gender gender
+ String name
+ Gender gender
- static constraints = {
- gender nullable: true
- }
+ static constraints = {
+ gender nullable: true
+ }
}
View
126 src/groovy/org/codehaus/groovy/grails/plugins/couchdb/ast/CouchEntityASTTransformation.groovy
@@ -109,14 +109,8 @@ class CouchEntityASTTransformation implements ASTTransformation {
private void injectEntityType(ClassNode classNode, AnnotationNode entity) {
- String typeValue = entity.members["type"]?.value
-
- if (typeValue == null) {
-
- // get the class name(s) including parent domain objects
- typeValue = getDomainClassHierarchy(classNode).toLowerCase()
- }
-
+ // get the class type
+ String typeValue = getDomainTypeValue(classNode, entity).toLowerCase()
String typeFieldName = entity.members["typeFieldName"]?.value ?: "type"
// inject the type property if it doesn't already exist
@@ -126,13 +120,13 @@ class CouchEntityASTTransformation implements ASTTransformation {
MethodNode getter = getLocalGetterMethod(classNode, getterName)
if (getter == null) {
getter = new MethodNode(getterName,
- Modifier.PUBLIC,
- STRING_TYPE,
- Parameter.EMPTY_ARRAY,
- null,
- new ReturnStatement(
- new ConstantExpression(typeValue)
- ))
+ Modifier.PUBLIC,
+ STRING_TYPE,
+ Parameter.EMPTY_ARRAY,
+ null,
+ new ReturnStatement(
+ new ConstantExpression(typeValue)
+ ))
setJsonPropertyAnnotation(getter, ["readOnly": ConstantExpression.TRUE])
@@ -189,19 +183,19 @@ class CouchEntityASTTransformation implements ASTTransformation {
private void fixupToStringMethod(ClassNode classNode, FieldNode idNode) {
- MethodNode method = classNode.getDeclaredMethod("toString", [] as Parameter[]);
+ MethodNode method = classNode.getDeclaredMethod("toString", [] as Parameter[])
if (method != null && method.lineNumber < 0 && (method.isPublic() || method.isProtected()) && !method.isAbstract()) {
- GStringExpression ge = new GStringExpression(classNode.getName() + ' : ${' + idNode.name + '}');
- ge.addString(new ConstantExpression(classNode.getName() + " : "));
- ge.addValue(new VariableExpression(idNode.name));
+ GStringExpression ge = new GStringExpression(classNode.getName() + ' : ${' + idNode.name + '}')
+ ge.addString(new ConstantExpression(classNode.getName() + " : "))
+ ge.addValue(new VariableExpression(idNode.name))
method.variableScope.removeReferencedClassVariable("id")
method.variableScope.putReferencedClassVariable(idNode)
- method.code = new ReturnStatement(ge);
+ method.code = new ReturnStatement(ge)
if (log.isDebugEnabled()) {
- log.debug("Changing method [toString()] on class [" + classNode.getName() + "] to use id field [" + id + "]");
+ log.debug("Changing method [toString()] on class [" + classNode.getName() + "] to use id field [" + id + "]")
}
}
}
@@ -330,13 +324,13 @@ class CouchEntityASTTransformation implements ASTTransformation {
MethodNode getter = getLocalGetterMethod(classNode, getterName)
if (getter == null) {
getter = new MethodNode(getterName,
- Modifier.PUBLIC,
- field.getType(),
- Parameter.EMPTY_ARRAY,
- null,
- new ReturnStatement(
- new FieldExpression(field)
- ))
+ Modifier.PUBLIC,
+ field.getType(),
+ Parameter.EMPTY_ARRAY,
+ null,
+ new ReturnStatement(
+ new FieldExpression(field)
+ ))
classNode.addMethod(getter)
}
@@ -349,15 +343,15 @@ class CouchEntityASTTransformation implements ASTTransformation {
MethodNode setter = getLocalSetterMethod(classNode, setterName)
if (setter == null) {
setter = new MethodNode(setterName,
- Modifier.PUBLIC,
- ClassHelper.VOID_TYPE,
- new Parameter(field.getType(), "value") as Parameter[],
- null,
- new ExpressionStatement(
- new BinaryExpression(
- new FieldExpression(field),
- Token.newSymbol(Types.EQUAL, -1, -1),
- new VariableExpression("value"))))
+ Modifier.PUBLIC,
+ ClassHelper.VOID_TYPE,
+ new Parameter(field.getType(), "value") as Parameter[],
+ null,
+ new ExpressionStatement(
+ new BinaryExpression(
+ new FieldExpression(field),
+ Token.newSymbol(Types.EQUAL, -1, -1),
+ new VariableExpression("value"))))
classNode.addMethod(setter)
}
@@ -369,8 +363,8 @@ class CouchEntityASTTransformation implements ASTTransformation {
for (Iterator it = field.annotations.iterator(); it.hasNext();) {
AnnotationNode node = (AnnotationNode) it.next()
if (JSON_PROPERTY.equals(node.getClassNode()) ||
- JSON_TYPE_HINT.equals(node.getClassNode()) ||
- JSON_CONVERTER.equals(node.getClassNode())) {
+ JSON_TYPE_HINT.equals(node.getClassNode()) ||
+ JSON_CONVERTER.equals(node.getClassNode())) {
it.remove()
}
@@ -455,36 +449,62 @@ class CouchEntityASTTransformation implements ASTTransformation {
private MethodNode getLocalGetterMethod(ClassNode classNode, String getterName) {
for (MethodNode method: classNode.getDeclaredMethods(getterName)) {
if (getterName.equals(method.getName())
- && ClassHelper.VOID_TYPE != method.getReturnType()
- && method.getParameters().length == 0) {
- return method;
+ && ClassHelper.VOID_TYPE != method.getReturnType()
+ && method.getParameters().length == 0) {
+
+ return method
}
}
- return null;
+ return null
}
private MethodNode getLocalSetterMethod(ClassNode classNode, String setterName) {
for (MethodNode method: classNode.getDeclaredMethods(setterName)) {
if (setterName.equals(method.getName())
- && ClassHelper.VOID_TYPE == method.getReturnType()
- && method.getParameters().length == 1) {
- return method;
+ && ClassHelper.VOID_TYPE == method.getReturnType()
+ && method.getParameters().length == 1) {
+
+ return method
}
}
- return null;
+ return null
}
- private String getDomainClassHierarchy(ClassNode classNode) {
- String name = classNode.nameWithoutPackage
+ private String getDomainTypeValue(ClassNode classNode, AnnotationNode entity) {
+
+ // get the type...
+ String name = entity.members["type"]?.value
+
+ // if set to empty string, then return as this disables the type field.
+ if (name == "") {
+ return name
+ }
- ClassNode parent = classNode.getSuperClass();
+ // if not set, then use the lower case class name
+ if (name == null) {
+ name = classNode.nameWithoutPackage.toLowerCase()
+ }
+
+ ClassNode parent = classNode.getSuperClass()
while (parent != null && !parent.getName().equals("java.lang.Object")) {
- if (parent.getAnnotations(COUCH_ENTITY)?.size() > 0) {
- name = parent.nameWithoutPackage + '.' + name
+ List<AnnotationNode> annotations = parent.getAnnotations(COUCH_ENTITY)
+
+ if (annotations?.size() > 0) {
+ String type = annotations[0].members["type"]?.value
+ if (type == null) {
+ type = parent.nameWithoutPackage.toLowerCase()
+ }
+
+ // if a type was specified (or defaulted), then prepend this
+ // to our current name.
+ if (type) {
+ name = type + (name ? '.' + name : '')
+ }
}
- parent = parent.getSuperClass();
+
+ parent = parent.getSuperClass()
}
return name
View
8 src/java/org/codehaus/groovy/grails/plugins/couchdb/domain/CouchDomainClass.java
@@ -137,7 +137,13 @@ public CouchDomainClass(Class<?> clazz, Map<String, Object> defaultConstraints,
documentType = (String) getter.invoke(clazz.newInstance());
}
} catch (Exception e) {
- log.error("Couldn't get document type for Class [" + clazz.getName() + "].", e);
+ if (e instanceof NoSuchMethodException && "".equals(entityAnnotation.type())) {
+ log.info("Document type is disabled for Class [" + clazz.getName() + "].");
+ } else {
+ log.error("Couldn't get document type for Class [" + clazz.getName() + "].", e);
+ }
+
+ documentType = "";
}
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(clazz);
View
2  test/integration/org/codehaus/groovy/grails/plugins/couchdb/test/DesignDocumentTests.groovy
@@ -57,7 +57,7 @@ class DesignDocumentTests extends GroovyTestCase {
def design = new DesignDocument();
// add a temporary "open" view
- design.addView("list", new View("function(doc) { if (doc.type == 'person.contact') { emit(doc.name, {name:doc.name, company:doc.company}); }}"))
+ design.addView("list", new View("function(doc) { if (doc.type == 'human.contact') { emit(doc.name, {name:doc.name, company:doc.company}); }}"))
// save the design document
Contact.saveDesignDocument(design)
View
23 test/integration/org/codehaus/groovy/grails/plugins/couchdb/test/InheritanceTests.groovy
@@ -17,6 +17,10 @@ package org.codehaus.groovy.grails.plugins.couchdb.test
import org.acme.Contact
import org.acme.Person
+import org.acme.Project
+import org.acme.Task
+import org.acme.NoType
+import javax.el.MethodNotFoundException
/**
*
@@ -24,14 +28,23 @@ import org.acme.Person
*/
class InheritanceTests extends GroovyTestCase {
- void testDefaultType() {
+ void testType() {
- def p = new Person()
- assertEquals "should be using the default type for person", 'person', p.type
+ assertEquals "should be using the defined type for Person", 'human', new Person().type
- def c = new Contact()
- assertEquals "should be using the default type for contact", 'person.contact', c.type
+ assertEquals "should be using the default type for Contact", 'human.contact', new Contact().type
+
+ assertEquals "should be using the default type for Project", 'project', new Project().type
+
+ assertEquals "should be using the assigned type and type field for Task", 'project-task', new Task().meta
+ try {
+ def type = new NoType().type
+ fail "The type field shouldn't exist on the NoType class."
+
+ } catch (Exception e) {
+ assertTrue "should have thrown a MissingPropertyException instead of ${e.class.name}", e instanceof MissingPropertyException
+ }
}
void testSubType() {
View
2  test/integration/org/codehaus/groovy/grails/plugins/couchdb/test/JsonGenerationTests.groovy
@@ -30,7 +30,7 @@ class JsonGenerationTests extends GroovyTestCase {
void testContact() {
// predefined json string for a contact
- String json = "{\"address\":{\"city\":\"Los Angeles\",\"state\":\"CA\",\"street1\":\"100 Hollywood Blvd.\",\"street2\":null,\"zip\":null},\"company\":\"Acme, Corp.\",\"gender\":\"MALE\",\"_id\":\"26b5811b3701c30c75d11f9a412103fa\",\"name\":\"Tom Jones\",\"type\":\"person.contact\",\"_rev\":\"2-ba19afa3cf78e7350202cf0c095c9aa4\"}"
+ String json = "{\"address\":{\"city\":\"Los Angeles\",\"state\":\"CA\",\"street1\":\"100 Hollywood Blvd.\",\"street2\":null,\"zip\":null},\"company\":\"Acme, Corp.\",\"gender\":\"MALE\",\"_id\":\"26b5811b3701c30c75d11f9a412103fa\",\"name\":\"Tom Jones\",\"type\":\"human.contact\",\"_rev\":\"2-ba19afa3cf78e7350202cf0c095c9aa4\"}"
def contact = new Contact()
Please sign in to comment.
Something went wrong with that request. Please try again.