Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
Conflicts:
	gedcomx-common/src/main/java/org/gedcomx/types/FactType.java
  • Loading branch information
daveyse committed Jun 26, 2012
2 parents 17af36c + abd1405 commit 397a9e6
Show file tree
Hide file tree
Showing 95 changed files with 7,934 additions and 2,272 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@
*.iws
target
.idea
*.zargo~
2 changes: 1 addition & 1 deletion enunciate-gedcomx-support/pom.xml
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.gedcomx</groupId>
<artifactId>gedcomx-parent</artifactId>
<version>0.14.0-SNAPSHOT</version>
<version>0.18.0-SNAPSHOT</version>
</parent>

<properties>
Expand Down
4 changes: 4 additions & 0 deletions enunciate-gedcomx-support/skin/css/style.css
Expand Up @@ -545,6 +545,10 @@ body.advisories #nav-advisories,body.community #nav-community,body.blog #nav-blo
margin-bottom: 10px;
}

#recipe {
max-height: 600px;
}

/* @end */
/* @group Footer */

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions enunciate-gedcomx-support/skin/loading.recipe.html
@@ -0,0 +1,5 @@
<html>
<body>
loading...
</body>
</html>
1 change: 1 addition & 0 deletions enunciate-gedcomx-support/skin/template.html
Expand Up @@ -38,6 +38,7 @@
<div id="primary" class="column span-13 last">
<ul class="navigation">
<li id="nav-about"><a href="About.html">About</a></li>
<li id="nav-specs"><a href="Specs.html">Specs</a></li>
<li id="nav-code"><a href="Developers-Guide.html">Dev</a></li>
<li id="nav-models"><a href="Data-Models.html">Models</a></li>
<li id="nav-profiles"><a href="Application-Profiles.html">API Profiles</a></li>
Expand Down
Expand Up @@ -46,6 +46,7 @@
import org.gedcomx.build.enunciate.rdf.RDFProcessor;
import org.gedcomx.build.enunciate.rs.*;
import org.gedcomx.rt.*;
import org.gedcomx.rt.GedcomNamespaceManager;
import org.gedcomx.rt.rs.ResourceDefinition;
import org.gedcomx.test.Recipe;

Expand Down
Expand Up @@ -25,64 +25,49 @@
import net.sf.jelly.apt.decorations.type.DecoratedClassType;
import net.sf.jelly.apt.decorations.type.DecoratedInterfaceType;
import net.sf.jelly.apt.decorations.type.DecoratedTypeMirror;
import org.codehaus.enunciate.apt.EnunciateFreemarkerModel;
import org.codehaus.enunciate.config.SchemaInfo;
import org.codehaus.enunciate.contract.jaxb.*;
import org.codehaus.enunciate.contract.jaxb.types.KnownXmlType;
import org.codehaus.enunciate.contract.jaxb.types.XmlClassType;
import org.codehaus.enunciate.contract.jaxb.types.XmlType;
import org.codehaus.enunciate.contract.validation.BaseValidator;
import org.codehaus.enunciate.contract.validation.ValidationResult;
import org.codehaus.enunciate.qname.XmlQNameEnum;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.annotate.JsonTypeIdResolver;
import org.gedcomx.rt.*;
import org.gedcomx.rt.json.JsonElementWrapper;

import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.namespace.QName;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
* @author Ryan Heaton
*/
public class GedcomxValidator extends BaseValidator {

@Override
public ValidationResult validateComplexType(ComplexTypeDefinition complexType) {
ValidationResult result = validateTypeDefinition(complexType);
if (!complexType.isFinal() && !complexType.isAbstract()) {
//validate the json type info.
// (heatonra, 9/12/2011) for the record, I looked into lifting the requirement to annotate all non-abstract, non-final
// classes with @JsonTypeInfo, @JsonTypeIdResolver and limiting its application to all classes that _extend_ non-abstract, non-final
// classes. Everything seemed to work fine until you came across lists/collections that could possibly be mixed. When
// Jackson deserializes a list of, e.g. RDFDescription that contains an instance of e.g. DublinCoreDescription then it pukes
// with a message like "unrecognized property" because it's attempting to deserialize a DublinCoreDescription into an instance
// of RDFDescription. Sigh. So it was decided that we'll continue with the policy of always writing out the type of non-final classes,
// at least until Jackson provides some more runtime flexibility.
JsonTypeInfo jsonTypeInfo = complexType.getAnnotation(JsonTypeInfo.class);
if (jsonTypeInfo == null || jsonTypeInfo.include() != JsonTypeInfo.As.PROPERTY || jsonTypeInfo.use() != JsonTypeInfo.Id.CUSTOM || !XmlTypeIdResolver.TYPE_PROPERTY_NAME.equals(jsonTypeInfo.property())) {
result.addError(complexType, "Non-final, non-abstract complex types need to be annotated with @JsonTypeInfo(use=JsonTypeInfo.Id.CUSTOM, property=\"@type\")");
}
private final Map<String, Declaration> jsonNameDeclarations = new HashMap<String, Declaration>();

String idResolverName = "";
JsonTypeIdResolver typeIdResolverInfo = complexType.getAnnotation(JsonTypeIdResolver.class);
if (typeIdResolverInfo != null) {
try {
idResolverName = typeIdResolverInfo.value().getName();
}
catch (MirroredTypeException e) {
idResolverName = ((DeclaredType) e.getTypeMirror()).getDeclaration().getQualifiedName();
@Override
public ValidationResult validate(EnunciateFreemarkerModel model) {
ValidationResult result = super.validate(model);
for (SchemaInfo schemaInfo : model.getNamespacesToSchemas().values()) {
for (Registry registry : schemaInfo.getRegistries()) {
Collection<LocalElementDeclaration> localElements = registry.getLocalElementDeclarations();
for (LocalElementDeclaration localElement : localElements) {
JsonElementWrapper elementWrapper = localElement.getAnnotation(JsonElementWrapper.class);
if (elementWrapper != null) {
String jsonName = elementWrapper.namespace() + elementWrapper.name();
Declaration previous = this.jsonNameDeclarations.put(jsonName, localElement);
if (previous != null) {
result.addError(localElement, "JSON name conflict with " + String.valueOf(previous.getPosition()));
}
}
}
}

if (!XmlTypeIdResolver.class.getName().equals(idResolverName)) {
result.addError(complexType, "Non-final, non-abstract complex types need to be annotated with @org.codehaus.jackson.map.annotate.JsonTypeIdResolver(org.gedcomx.id.XmlTypeIdResolver.class) to specify their JSON type id.");
}

if (!suppressWarning(complexType, "gedcomx:no_id") && !hasIdAttribute(complexType)) {
result.addWarning(complexType, "Non-final, non-abstract complex types might need to have an 'id' attribute so they can be referenced.");
}
}
return result;
}
Expand All @@ -92,24 +77,6 @@ private boolean suppressWarning(Declaration declaration, String warning) {
return suppressionInfo != null && Arrays.asList(suppressionInfo.value()).contains(warning);
}

protected boolean hasIdAttribute(ComplexTypeDefinition complexType) {
boolean idAttributeFound = false;
for (Attribute attribute : complexType.getAttributes()) {
if (attribute.isXmlID()) {
idAttributeFound = true;
break;
}
}
XmlType baseType = complexType.getBaseType();
if (baseType instanceof XmlClassType) {
TypeDefinition typeDefinition = ((XmlClassType) baseType).getTypeDefinition();
if (typeDefinition.isComplex()) {
idAttributeFound = hasIdAttribute((ComplexTypeDefinition) typeDefinition);
}
}
return idAttributeFound;
}

@Override
public ValidationResult validateSimpleType(SimpleTypeDefinition simpleType) {
return validateTypeDefinition(simpleType);
Expand All @@ -124,38 +91,31 @@ public ValidationResult validateEnumType(EnumTypeDefinition enumType) {
public ValidationResult validateRootElement(RootElementDeclaration rootElementDeclaration) {
ValidationResult result = super.validateRootElement(rootElementDeclaration);
String namespace = rootElementDeclaration.getNamespace();
if (namespace == null || "".equals(namespace)) {
if (namespace == null) {
namespace = "";
}

if (namespace.isEmpty()) {
result.addError(rootElementDeclaration, "Root element should not be in the empty namespace.");
}

if (rootElementDeclaration.getName().toLowerCase().startsWith("web")) {
result.addWarning(rootElementDeclaration, "You probably don't want a root element that starts with the name 'web'. Consider renaming using the @XmlRootElement annotation.");
}

JsonTypeInfo jsonTypeInfo = rootElementDeclaration.getAnnotation(JsonTypeInfo.class);
if (jsonTypeInfo == null || jsonTypeInfo.include() != JsonTypeInfo.As.PROPERTY || jsonTypeInfo.use() != JsonTypeInfo.Id.CUSTOM || !XmlTypeIdResolver.TYPE_PROPERTY_NAME.equals(jsonTypeInfo.property())) {
result.addError(rootElementDeclaration, "Root elements need to be annotated with @JsonTypeInfo(use=JsonTypeInfo.Id.CUSTOM, property=\"@type\")");
JsonElementWrapper elementWrapper = rootElementDeclaration.getAnnotation(JsonElementWrapper.class);
if (namespace.startsWith(CommonModels.GEDCOMX_DOMAIN) && elementWrapper == null) {
result.addWarning(rootElementDeclaration, "Root elements in the '" + CommonModels.GEDCOMX_DOMAIN + "' namespace should probably be annotated with @" + JsonElementWrapper.class.getSimpleName() + ".");
}

String idResolverName = "";
JsonTypeIdResolver typeIdResolverInfo = rootElementDeclaration.getAnnotation(JsonTypeIdResolver.class);
if (typeIdResolverInfo != null) {
try {
idResolverName = typeIdResolverInfo.value().getName();
}
catch (MirroredTypeException e) {
idResolverName = ((DeclaredType) e.getTypeMirror()).getDeclaration().getQualifiedName();
if (elementWrapper != null) {
String jsonName = elementWrapper.namespace() + elementWrapper.name();
Declaration previous = this.jsonNameDeclarations.put(jsonName, rootElementDeclaration);
if (previous != null) {
result.addError(rootElementDeclaration, "JSON name conflict with " + String.valueOf(previous.getPosition()));
}
}

if (!XmlTypeIdResolver.class.getName().equals(idResolverName)) {
result.addError(rootElementDeclaration, "Root elements need to be annotated with @org.codehaus.jackson.map.annotate.JsonTypeIdResolver(org.gedcomx.id.XmlTypeIdResolver.class) to specify their JSON type id.");
}

if (namespace.startsWith(CommonModels.GEDCOMX_DOMAIN) && rootElementDeclaration.getAnnotation(JsonElementWrapper.class) == null) {
result.addWarning(rootElementDeclaration, "Root elements in the '" + CommonModels.GEDCOMX_DOMAIN + "' namespace should probably be annotated with @" + JsonElementWrapper.class.getSimpleName() + ".");
}

return result;
}

Expand Down Expand Up @@ -187,10 +147,6 @@ public ValidationResult validateTypeDefinition(TypeDefinition typeDef) {
}
}

if ("persistentId".equalsIgnoreCase(attribute.getName())) {
result.addWarning(attribute, "Persistent IDs should be elements to conform to the established pattern.");
}

TypeMirror accessorType = attribute.getAccessorType();
if (accessorType instanceof EnumType && ((EnumType) accessorType).getDeclaration().getAnnotation(XmlQNameEnum.class) != null) {
result.addError(attribute, "Accessors should not reference QName enums directly. You probably want to annotate this accessor with @XmlTransient.");
Expand Down Expand Up @@ -224,23 +180,11 @@ public ValidationResult validateTypeDefinition(TypeDefinition typeDef) {
result.addError(choice, "Entity links should be make with an attribute named 'href'. You probably need to apply @XmlAttribute.");
}

if ("persistentId".equals(choice.getName()) && !isURI) {
result.addError(choice, "Accessors named 'persistentId' should be elements of type URI.");
}

TypeMirror accessorType = choice.getAccessorType();
if (accessorType instanceof EnumType && ((EnumType) accessorType).getDeclaration().getAnnotation(XmlQNameEnum.class) != null) {
result.addError(choice, "Accessors should not reference QName enums directly. You probably want to annotate this accessor with @XmlTransient.");
}

accessorType = choice.getBareAccessorType();
if (accessorType instanceof DeclaredType) {
if ("alternateid".equals(((DeclaredType)accessorType).getDeclaration().getSimpleName().toLowerCase()) &&
(!"alternateId".equals(element.getName()) || element.isWrapped())) {
result.addWarning(element, "Element name for AlternateId should probably be named 'alternateId' to be consistent.");
}
}

QName ref = choice.getRef();
String ns = ref != null ? ref.getNamespaceURI() : choice.getNamespace();
if (ns == null || "".equals(ns)) {
Expand Down
Expand Up @@ -15,21 +15,24 @@
*/
package org.gedcomx.build.enunciate;

import com.sun.mirror.type.ClassType;
import com.sun.mirror.type.InterfaceType;
import net.sf.jelly.apt.decorations.TypeMirrorDecorator;
import net.sf.jelly.apt.decorations.type.DecoratedClassType;
import net.sf.jelly.apt.decorations.type.DecoratedInterfaceType;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.TypeMirror;
import net.sf.jelly.apt.decorations.type.DecoratedTypeMirror;
import org.codehaus.enunciate.apt.EnunciateFreemarkerModel;
import org.codehaus.enunciate.contract.jaxb.Element;
import org.codehaus.enunciate.contract.jaxb.TypeDefinition;
import org.codehaus.enunciate.contract.jaxb.types.XmlClassType;
import org.codehaus.enunciate.contract.jaxb.types.XmlType;
import org.codehaus.enunciate.doc.DocumentationExample;
import org.codehaus.enunciate.modules.docs.WhateverNode;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import org.gedcomx.rt.SupportsExtensionAttributes;
import org.gedcomx.rt.SupportsExtensionElements;
import org.gedcomx.rt.XmlTypeIdResolver;
import org.gedcomx.rt.json.HasJsonKey;
import org.gedcomx.rt.json.HasUniqueJsonKey;
import org.gedcomx.rt.json.JsonSimpleValue;

/**
* @author Ryan Heaton
Expand All @@ -40,43 +43,70 @@ public GenerateExampleJsonMethod(EnunciateFreemarkerModel model) {
super(model);
}

protected void generateExampleJson(TypeDefinition type, ObjectNode jsonNode, int maxDepth) {
if (type != null) {
if (!jsonNode.has(XmlTypeIdResolver.TYPE_PROPERTY_NAME) && type.getAnnotation(JsonTypeInfo.class) != null) {
jsonNode.put(XmlTypeIdResolver.TYPE_PROPERTY_NAME, JsonNodeFactory.instance.textNode(type.getNamespace() + type.getName()));
@Override
protected void generateExampleJson(Element element, ObjectNode jsonNode, int maxDepth) {
if (element.isCollectionType() && ((DecoratedTypeMirror)element.getBareAccessorType()).isInstanceOf(HasJsonKey.class.getName())) {
String jsonName = element.getJsonMemberName();
ObjectNode on = JsonNodeFactory.instance.objectNode();
JsonNode val = generateExampleJson(element.getBaseType(), "...", maxDepth);
JsonNode ex;
boolean isUnique = ((DecoratedTypeMirror)element.getBareAccessorType()).isInstanceOf(HasUniqueJsonKey.class.getName());
if (!isUnique) {
ArrayNode exs = JsonNodeFactory.instance.arrayNode();
exs.add(val);
exs.add(WhateverNode.instance);
ex = exs;
}

super.generateExampleJson(type, jsonNode, maxDepth);

if (isInstanceOf(type, SupportsExtensionAttributes.class.getName())) {
jsonNode.put("http://extension/attribute", JsonNodeFactory.instance.textNode("..."));
else {
ex = val;
}

if (isInstanceOf(type, SupportsExtensionElements.class.getName())) {
ArrayNode exampleValues = JsonNodeFactory.instance.arrayNode();
exampleValues.add(WhateverNode.instance);
exampleValues.add(WhateverNode.instance);
jsonNode.put("http://extension/element", exampleValues);
exampleValues = JsonNodeFactory.instance.arrayNode();
exampleValues.add(WhateverNode.instance);
exampleValues.add(WhateverNode.instance);
jsonNode.put("extension", exampleValues);
on.put("type1", ex);
on.put("type2", ex);
on.put("...", WhateverNode.instance);
jsonNode.put(jsonName, on);
}
else {
String simpleValue = getSimpleValue(element);
if (simpleValue != null) {
jsonNode.put(element.getJsonMemberName(), simpleValue);
}
else {
super.generateExampleJson(element, jsonNode, maxDepth);
}
}
}

private boolean isInstanceOf(TypeDefinition typeDef, String name) {
for (InterfaceType interfaceType : typeDef.getSuperinterfaces()) {
if (((DecoratedInterfaceType) TypeMirrorDecorator.decorate(interfaceType)).isInstanceOf(name)) {
return true;
private String getSimpleValue(Element element) {
String val = null;
TypeMirror accessorType = element.getAccessorType();
if (accessorType instanceof DeclaredType) {
TypeDeclaration decl = ((DeclaredType) accessorType).getDeclaration();
if (decl != null) {
JsonSimpleValue sv = decl.getAnnotation(JsonSimpleValue.class);
if (sv != null) {
DocumentationExample example = element.getAnnotation(DocumentationExample.class);
val = example == null || "##default".equals(example.value()) ? "##default".equals(sv.example()) ? "..." : sv.example() : example.value();
}
}
}
return val;
}

ClassType superclass = typeDef.getSuperclass();
if (superclass != null && ((DecoratedClassType) TypeMirrorDecorator.decorate(superclass)).isInstanceOf(name)) {
return true;
@Override
protected JsonNode generateExampleJson(XmlType type, String specifiedValue, int maxDepth) {
if (type instanceof XmlClassType) {
TypeDefinition typeDef = ((XmlClassType) type).getTypeDefinition();
JsonSimpleValue sv = typeDef == null ? null : typeDef.getAnnotation(JsonSimpleValue.class);
if (sv != null) {
if ("...".equals(specifiedValue) && !"##default".equals(sv.example())) {
specifiedValue = sv.example();
}
return JsonNodeFactory.instance.textNode(specifiedValue);
}
}

return false;
return super.generateExampleJson(type, specifiedValue, maxDepth);
}

}

0 comments on commit 397a9e6

Please sign in to comment.