org.jpmml.xjc.InheritancePlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pmml-xjc Show documentation
Show all versions of pmml-xjc Show documentation
JPMML XJC plugins for programmatic class model customization
/*
* Copyright (c) 2015 Villu Ruusmann
*/
package org.jpmml.xjc;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.transform.dom.DOMSource;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CClassRef;
import com.sun.tools.xjc.model.CPluginCustomization;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.tools.xjc.model.Model;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIClass;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlValue;
import org.xml.sax.ErrorHandler;
public class InheritancePlugin extends ComplexPlugin {
@Override
public String getOptionName(){
return "Xinheritance";
}
@Override
public String getUsage(){
return null;
}
@Override
public List getCustomizationElementNames(){
return Arrays.asList(InheritancePlugin.EXTENDS_ELEMENT_NAME, InheritancePlugin.IMPLEMENTS_ELEMENT_NAME);
}
@Override
public void postProcessModel(Model model, ErrorHandler errorHandler){
super.postProcessModel(model, errorHandler);
Map classRefCache = new HashMap<>();
CClassRef defaultBaseClazz = getClassRef(classRefCache, model, "org.dmg.pmml.PMMLObject");
Collection classInfos = (model.beans()).values();
for(CClassInfo classInfo : classInfos){
CClassRef baseClazz = defaultBaseClazz;
CPluginCustomization extendsCustomization = CustomizationUtil.findCustomization(classInfo, InheritancePlugin.EXTENDS_ELEMENT_NAME);
if(extendsCustomization != null){
ExtendsClass extendsClass = (ExtendsClass)unmarshal(extendsCustomization);
String name = extendsClass.className;
int lt = name.indexOf('<');
if(lt > -1){
name = name.substring(0, lt);
}
baseClazz = getClassRef(classRefCache, model, name);
}
classInfo.setBaseClass(baseClazz);
}
}
@Override
public boolean run(Outline outline, Options options, ErrorHandler errorHandler){
JCodeModel codeModel = outline.getCodeModel();
Map typeCache = new HashMap<>();
Collection extends ClassOutline> classOutlines = outline.getClasses();
for(ClassOutline classOutline : classOutlines){
JDefinedClass beanClazz = classOutline.implClass;
CPluginCustomization extendsCustomization = CustomizationUtil.findCustomization(classOutline, InheritancePlugin.EXTENDS_ELEMENT_NAME);
if(extendsCustomization != null){
ExtendsClass extendsClass = (ExtendsClass)unmarshal(extendsCustomization);
JClass type = parseType(typeCache, codeModel, extendsClass.className);
beanClazz._extends(type);
}
List implementsCustomizations = CustomizationUtil.findCustomizations(classOutline, InheritancePlugin.IMPLEMENTS_ELEMENT_NAME);
for(CPluginCustomization implementsCustomization : implementsCustomizations){
ImplementsInterface implementsInterface = (ImplementsInterface)unmarshal(implementsCustomization);
JClass type = parseType(typeCache, codeModel, implementsInterface.interfaceName);
beanClazz._implements(type);
}
// See https://github.com/highsource/jaxb2-basics/issues/70
FieldOutline[] fieldOutlines = classOutline.getDeclaredFields();
for(FieldOutline fieldOutline : fieldOutlines){
CPropertyInfo propertyInfo = fieldOutline.getPropertyInfo();
CustomizationUtil.findPropertyCustomizationsInProperty(propertyInfo, InheritancePlugin.EXTENDS_ELEMENT_NAME);
CustomizationUtil.findPropertyCustomizationsInProperty(propertyInfo, InheritancePlugin.IMPLEMENTS_ELEMENT_NAME);
}
}
return true;
}
static
private JClass parseType(Map typeCache, JCodeModel codeModel, String name){
JClass type = typeCache.get(name);
if(type == null){
try {
type = (JClass)codeModel.parseType(name);
} catch(ClassNotFoundException cnfe){
throw new RuntimeException(cnfe);
}
typeCache.put(name, type);
}
return type;
}
static
private CClassRef getClassRef(Map classRefCache, Model model, String name){
CClassRef classRef = classRefCache.get(name);
if(classRef == null){
classRef = new CClassRef(model, null, createBIClass(name), null);
classRefCache.put(name, classRef);
}
return classRef;
}
@SuppressWarnings("deprecation")
static
private BIClass createBIClass(String name){
try {
Constructor extends BIClass> biClassConstructor = BIClass.class.getDeclaredConstructor();
if(!biClassConstructor.isAccessible()){
biClassConstructor.setAccessible(true);
}
BIClass biClass = biClassConstructor.newInstance();
Field refField = BIClass.class.getDeclaredField("ref");
if(!refField.isAccessible()){
refField.setAccessible(true);
}
refField.set(biClass, name);
return biClass;
} catch(Exception e){
throw new RuntimeException(e);
}
}
static
private Object unmarshal(CPluginCustomization customization){
try {
Unmarshaller unmarshaller = InheritancePlugin.context.createUnmarshaller();
return unmarshaller.unmarshal(new DOMSource(customization.element));
} catch(Exception e){
throw new RuntimeException(e);
}
}
public static final String NAMESPACE_URI = "http://jaxb2-commons.dev.java.net/basic/inheritance";
public static final QName EXTENDS_ELEMENT_NAME = new QName(InheritancePlugin.NAMESPACE_URI, "extends");
public static final QName IMPLEMENTS_ELEMENT_NAME = new QName(InheritancePlugin.NAMESPACE_URI, "implements");
@XmlRootElement (
namespace = NAMESPACE_URI,
name = "extends"
)
static
public class ExtendsClass {
@XmlValue
public String className;
}
@XmlRootElement (
namespace = NAMESPACE_URI,
name = "implements"
)
static
public class ImplementsInterface {
@XmlValue
public String interfaceName;
}
private static final JAXBContext context;
static {
try {
context = JAXBContext.newInstance(ExtendsClass.class, ImplementsInterface.class);
} catch(Exception e){
throw new RuntimeException(e);
}
}
}