package org.jvnet.jaxb2_commons.plugin.inheritance.util;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.type.PrimitiveType;
import japa.parser.ast.type.ReferenceType;
import japa.parser.ast.type.Type;
import japa.parser.ast.type.VoidType;
import japa.parser.ast.type.WildcardType;
import japa.parser.ast.visitor.GenericVisitorAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JType;
public class TypeToJTypeConvertingVisitor extends
GenericVisitorAdapter<JType, JCodeModel> {
private final Map<String, JClass> knownClasses;
public TypeToJTypeConvertingVisitor(Map<String, JClass> knownClasses) {
Validate.notNull(knownClasses);
this.knownClasses = knownClasses;
}
@Override
public JType visit(VoidType type, JCodeModel codeModel) {
return codeModel.VOID;
}
@Override
public JType visit(PrimitiveType type, JCodeModel codeModel) {
switch (type.getType()) {
case Boolean:
return codeModel.BOOLEAN;
case Char:
return codeModel.CHAR;
case Byte:
return codeModel.BYTE;
case Short:
return codeModel.SHORT;
case Int:
return codeModel.INT;
case Long:
return codeModel.LONG;
case Float:
return codeModel.FLOAT;
case Double:
return codeModel.DOUBLE;
default:
throw new AssertionError("Unknown primitive type ["
+ type.getType() + "]");
}
}
@Override
public JType visit(ReferenceType type, JCodeModel codeModel) {
final JType referencedType = type.getType().accept(this, codeModel);
JType referencedTypeArray = referencedType;
for (int index = 0; index < type.getArrayCount(); index++) {
referencedTypeArray = referencedTypeArray.array();
}
return referencedTypeArray;
}
@Override
public JType visit(WildcardType type, JCodeModel codeModel) {
if (type.getExtends() != null) {
final ReferenceType _extends = type.getExtends();
final JType boundType = _extends.accept(this, codeModel);
if (!(boundType instanceof JClass)) {
throw new IllegalArgumentException("Bound type [" + _extends
+ "]in the wildcard type must be class.");
}
final JClass boundClass = (JClass) boundType;
return boundClass.wildcard();
} else if (type.getSuper() != null) {
// TODO
throw new IllegalArgumentException(
"Wildcard types with super clause are not supported at the moment.");
} else {
throw new IllegalArgumentException(
"Wildcard type must have either extends or super clause.");
}
}
@Override
public JType visit(ClassOrInterfaceType type, JCodeModel codeModel) {
final String name = getName(type);
final JClass knownClass = this.knownClasses.get(name);
final JClass jclass = knownClass != null ? knownClass : codeModel
.ref(name);
final List<Type> typeArgs = type.getTypeArgs();
if (typeArgs == null || typeArgs.isEmpty()) {
return jclass;
} else {
final List<JClass> jtypeArgs = new ArrayList<JClass>(
typeArgs.size());
for (Type typeArg : typeArgs) {
final JType jtype = typeArg.accept(this, codeModel);
if (!(jtype instanceof JClass)) {
throw new IllegalArgumentException("Type argument ["
+ typeArg.toString() + "] is not a class.");
} else {
jtypeArgs.add((JClass) jtype);
}
}
return jclass.narrow(jtypeArgs);
}
}
private String getName(ClassOrInterfaceType type) {
final String name = type.getName();
final ClassOrInterfaceType scope = type.getScope();
if (scope == null) {
return name;
} else {
return getName(scope) + "." + name;
}
}
}