Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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.