com.vmware.vcloud.xjcplugin.JsonMappingInfoPlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vcd-xjc-plugins Show documentation
Show all versions of vcd-xjc-plugins Show documentation
Custom plugins for XML to Java Compilation
package com.vmware.vcloud.xjcplugin;
/*-
* #%L
* vcd-xjc-plugins :: Custom plugins for XML to Java Compilation
* %%
* Copyright (C) 2018 VMware, Inc.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.ErrorHandler;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.sun.codemodel.JAnnotatable;
import com.sun.codemodel.JAnnotationArrayMember;
import com.sun.codemodel.JAnnotationUse;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.model.CCustomizations;
import com.sun.tools.xjc.model.CPluginCustomization;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.Outline;
import org.jvnet.jaxb2_commons.util.CustomizationUtils;
/**
* JsonMappingInfoPlugin
is a plug-in for the JAXB's XJC code generator. It adds
* {@link JsonTypeInfo} and {@link JsonSubTypes} annotations to the generated JAXB classes. This
* facilitates mapping between abstract types and JSON objects
*
* To activate it, add the following parameters to the XJC command line:
*
*
* -enable -Xjsonapi
*
*
* Add the following to parent type
* in the XSD:
*
*
* <xs:appinfo>
* <meta:jsonTypeInfo propertyName="type" />
* </xs:appinfo>
*
*
* Add the following to any sub type(s) in the XSD:
*
*
* <xs:appinfo>
* <meta:jsonSubTypeInfo name="string" />
* </xs:appinfo>
*
*
*
*
* You also have to add the following boilerplate to the beginning of the XSD:
*
*
* xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
* xmlns:meta="http://www.vmware.com/vcloud/meta"
* jaxb:verion="2.0"
* jaxb:extensionBindingPrefixes="meta"
*
*/
public class JsonMappingInfoPlugin extends Plugin {
private static final String X_ANNOTATION_JSON_TYPE_PROPERTY_NAME = "propertyName";
private static final String X_ANNOTATION_JSON_SUBTYPE_NAME = "name";
private static final String NAMESPACE_URI = "http://www.vmware.com/vcloud/plugin/json";
private static final String ELEMENT_JSON_TYPE = "jsonTypeInfo";
private static final String ELEMENT_JSON_SUBTYPE_TYPE = "jsonSubTypeInfo";
private static final String PLUGIN_OPTION = "Xjson-api";
@Override
public String getOptionName() {
return PLUGIN_OPTION;
}
@Override
public List getCustomizationURIs() {
ArrayList res = new ArrayList(1);
res.add(NAMESPACE_URI);
return res;
}
@Override
public boolean isCustomizationTagName(String nsUri, String localName) {
return NAMESPACE_URI.equals(nsUri)
&& (ELEMENT_JSON_TYPE.equals(localName) || ELEMENT_JSON_SUBTYPE_TYPE.equals(localName));
}
@Override
public String getUsage() {
return " -" + PLUGIN_OPTION + ": enables the plugin\n";
}
@Override
public boolean run(Outline outline, Options options, ErrorHandler errorHandler) {
for (ClassOutline classOutline : outline.getClasses()) {
final CCustomizations customizations = CustomizationUtils.getCustomizations(classOutline);
addJsonMappingAnnotations(classOutline, customizations);
}
return true;
}
/**
* Adds {@link JsonTypeInfo} or {@link JsonSubTypes} annotations to the given element based on
* the schema annotations present.
*
* @param classOutline
* {@link ClassOutline} for the element which will be annotated
* @param customizations
* schema customizations for this element
*/
private void addJsonMappingAnnotations(
final ClassOutline classOutline,
final CCustomizations customizations) {
final JAnnotatable annotatable = classOutline.implClass;
if (annotatable == null) {
return;
}
final CPluginCustomization parentTypeCustomization = customizations.find(NAMESPACE_URI, ELEMENT_JSON_TYPE);
if (parentTypeCustomization != null) {
String typePropertyName = null;
parentTypeCustomization.markAsAcknowledged();
if (parentTypeCustomization.element.hasAttribute(X_ANNOTATION_JSON_TYPE_PROPERTY_NAME)) {
typePropertyName = parentTypeCustomization.element.getAttribute(X_ANNOTATION_JSON_TYPE_PROPERTY_NAME);
}
final JAnnotationUse annotation = annotatable.annotate(JsonTypeInfo.class);
annotation.param("use", JsonTypeInfo.Id.NAME);
annotation.param("include", JsonTypeInfo.As.PROPERTY);
annotation.param("property", typePropertyName);
}
final CPluginCustomization subTypeCustomization =
customizations.find(NAMESPACE_URI, ELEMENT_JSON_SUBTYPE_TYPE);
if (subTypeCustomization != null) {
String typeName = null;
subTypeCustomization.markAsAcknowledged();
if (subTypeCustomization.element.hasAttribute(X_ANNOTATION_JSON_SUBTYPE_NAME)) {
typeName = subTypeCustomization.element.getAttribute(X_ANNOTATION_JSON_SUBTYPE_NAME);
}
final JAnnotatable annotatableParent = classOutline.getSuperClass().implClass;
JAnnotationArrayMember annotationValues = null;
for (JAnnotationUse annot : annotatableParent.annotations()) {
if (annot.getAnnotationClass().fullName().equals(JsonSubTypes.class.getCanonicalName())) {
annotationValues = (JAnnotationArrayMember)annot.getAnnotationMembers().get("value");
break;
}
}
if (annotationValues == null) {
annotationValues = annotatableParent.annotate(JsonSubTypes.class).paramArray("value");
}
annotationValues.annotate(JsonSubTypes.Type.class).param("value", classOutline.implClass).param("name", typeName);
}
}
}