Skip to content

Commit

Permalink
Improved class model generation
Browse files Browse the repository at this point in the history
All PMMLObject subclasses are expected to have type-level
@XmlRootElement and @JsonRootName annotations.
  • Loading branch information
vruusmann committed Nov 20, 2024
1 parent b1295d5 commit 8777fb0
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.dmg.pmml.time_series.TrendExpoSmooth;
import org.jpmml.model.ReflectionUtil;
import org.jpmml.model.UnsupportedAttributeException;
import org.jpmml.model.UnsupportedElementException;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -159,7 +160,7 @@ public void downgradeTrendExpoSmooth(){

try {
downgrade(trendExpoSmooth, Version.PMML_4_0);
} catch(IllegalArgumentException iae){
} catch(UnsupportedElementException uee){
// Ignored
}
}
Expand Down
94 changes: 94 additions & 0 deletions pmml-xjc/src/main/java/org/jpmml/xjc/CodeModelUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@
*/
package org.jpmml.xjc;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

import com.sun.codemodel.JAnnotatable;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JFormatter;
import com.sun.codemodel.JGenerable;
import com.sun.codemodel.JType;

public class CodeModelUtil {
Expand All @@ -24,4 +33,89 @@ public JType getElementType(JType collectionType){

return elementTypes.get(0);
}

static
public boolean hasAnnotation(Collection<JAnnotationUse> annotations, Class<?> clazz){
JAnnotationUse annotation = findAnnotation(annotations, clazz);

return (annotation != null);
}

static
public JAnnotationUse findAnnotation(Collection<JAnnotationUse> annotations, Class<?> clazz){
String fullName = clazz.getName();

for(JAnnotationUse annotation : annotations){
JClass type = annotation.getAnnotationClass();

if((type.fullName()).equals(fullName)){
return annotation;
}
}

return null;
}

static
public List<JAnnotationUse> getAnnotations(JAnnotatable annotatable){

try {
Class<?> clazz = annotatable.getClass();

Field annotationsField;

while(true){

try {
annotationsField = clazz.getDeclaredField("annotations");

break;
} catch(NoSuchFieldException nsfe){
clazz = clazz.getSuperclass();

if(clazz == null){
throw nsfe;
}
}
}

ensureAccessible(annotationsField);

return (List)annotationsField.get(annotatable);
} catch(ReflectiveOperationException roe){
throw new RuntimeException(roe);
}
}

static
public String stringValue(JGenerable generable){
String result;

try(StringWriter writer = new StringWriter()){
generable.generate(new JFormatter(writer));

result = writer.toString();
} catch(IOException ioe){
throw new RuntimeException(ioe);
}

if(result.length() >= 2 && (result.startsWith("\"") && result.endsWith("\""))){
result = result.substring(1, result.length() - 1);
} else

{
throw new RuntimeException();
}

return result;
}

@SuppressWarnings("deprecation")
static
void ensureAccessible(AccessibleObject accessibleObject){

if(!accessibleObject.isAccessible()){
accessibleObject.setAccessible(true);
}
}
}
14 changes: 10 additions & 4 deletions pmml-xjc/src/main/java/org/jpmml/xjc/JacksonPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.sun.codemodel.JAnnotationArrayMember;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JAnnotationValue;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
Expand All @@ -38,6 +39,7 @@
import com.sun.tools.xjc.outline.EnumOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import jakarta.xml.bind.annotation.XmlRootElement;
import org.xml.sax.ErrorHandler;

public class JacksonPlugin extends Plugin {
Expand All @@ -58,14 +60,18 @@ public boolean run(Outline outline, Options options, ErrorHandler errorHandler){

Collection<? extends ClassOutline> classOutlines = outline.getClasses();
for(ClassOutline classOutline : classOutlines){
CClassInfo classInfo = classOutline.target;
JDefinedClass beanClazz = classOutline.implClass;

if(classInfo.isElement()){
QName elementName = classInfo.getElementName();
List<JAnnotationUse> beanClazzAnnotations = CodeModelUtil.getAnnotations(beanClazz);

JAnnotationUse xmlRootElement = CodeModelUtil.findAnnotation(beanClazzAnnotations, XmlRootElement.class);
if(xmlRootElement != null){
Map<String, JAnnotationValue> annotationMembers = xmlRootElement.getAnnotationMembers();

JAnnotationValue nameValue = annotationMembers.get("name");

JAnnotationUse jsonRootName = beanClazz.annotate(JsonRootName.class)
.param("value", elementName.getLocalPart());
.param("value", CodeModelUtil.stringValue(nameValue));
}

FieldOutline[] fieldOutlines = classOutline.getDeclaredFields();
Expand Down
Loading

0 comments on commit 8777fb0

Please sign in to comment.