String fullName = typeDescr.getType().getFullName();
if (type.getKind().equals(TypeDeclaration.Kind.CLASS)) {
TypeDeclarationDescr tdescr = (TypeDeclarationDescr) typeDescr;
if (tdescr.getSuperTypes().size() > 1) {
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, "Declared class " + fullName + " - has more than one supertype;"));
return;
} else if (tdescr.getSuperTypes().isEmpty()) {
tdescr.addSuperType("java.lang.Object");
}
}
AnnotationDescr traitableAnn = typeDescr.getAnnotation(Traitable.class.getSimpleName());
boolean traitable = traitableAnn != null;
String[] fullSuperTypes = new String[typeDescr.getSuperTypes().size() + 1];
int j = 0;
for (QualifiedName qname : typeDescr.getSuperTypes()) {
fullSuperTypes[j++] = qname.getFullName();
}
fullSuperTypes[j] = Thing.class.getName();
List<String> interfaceList = new ArrayList<String>();
interfaceList.add(traitable ? Externalizable.class.getName() : Serializable.class.getName());
if (traitable) {
interfaceList.add(TraitableBean.class.getName());
}
String[] interfaces = interfaceList.toArray(new String[interfaceList.size()]);
// prepares a class definition
ClassDefinition def;
switch (type.getKind()) {
case TRAIT:
def = new ClassDefinition(fullName,
"java.lang.Object",
fullSuperTypes);
break;
case ENUM:
def = new EnumClassDefinition(fullName,
fullSuperTypes[0],
null);
break;
case CLASS:
default:
def = new ClassDefinition(fullName,
fullSuperTypes[0],
interfaces);
def.setTraitable(traitable, traitableAnn != null &&
traitableAnn.getValue("logical") != null &&
Boolean.valueOf(traitableAnn.getValue("logical")));
}
for (String annotationName : typeDescr.getAnnotationNames()) {
Class annotation = resolveAnnotation(annotationName,
pkgRegistry.getTypeResolver());
if (annotation != null && annotation.isAnnotation()) {
try {
AnnotationDefinition annotationDefinition = AnnotationDefinition.build(annotation,
typeDescr.getAnnotations().get(annotationName).getValueMap(),
pkgRegistry.getTypeResolver());
def.addAnnotation(annotationDefinition);
} catch (NoSuchMethodException nsme) {
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr,
"Annotated type " + fullName +
" - undefined property in @annotation " +
annotationName + ": " +
nsme.getMessage() + ";"));
}
}
if (annotation == null || annotation == Role.class) {
def.addMetaData(annotationName, typeDescr.getAnnotation(annotationName).getSingleValue());
}
}
// add enum literals, if appropriate
if (type.getKind() == TypeDeclaration.Kind.ENUM) {
for (EnumLiteralDescr lit : ((EnumDeclarationDescr) typeDescr).getLiterals()) {
((EnumClassDefinition) def).addLiteral(
new EnumLiteralDefinition(lit.getName(), lit.getConstructorArgs())
);
}
}
// fields definitions are created. will be used by subclasses, if any.
// Fields are SORTED in the process
if (!typeDescr.getFields().isEmpty()) {
PriorityQueue<FieldDefinition> fieldDefs = sortFields(typeDescr.getFields(),
pkgRegistry);
int n = fieldDefs.size();
for (int k = 0; k < n; k++) {
FieldDefinition fld = fieldDefs.poll();
if (unresolvedTypeDefinitions != null) {
for (TypeDefinition typeDef : unresolvedTypeDefinitions) {
if (fld.getTypeName().equals(typeDef.getTypeClassName())) {
fld.setRecursive(true);
break;
}
}
}
fld.setIndex(k);
def.addField(fld);
}
}
// check whether it is necessary to build the class or not
Class<?> existingDeclarationClass = getExistingDeclarationClass(typeDescr);
type.setNovel(existingDeclarationClass == null);
// attach the class definition, it will be completed later
type.setTypeClassDef(def);
//if is not new, search the already existing declaration and
//compare them o see if they are at least compatibles
if (!type.isNovel()) {
TypeDeclaration previousTypeDeclaration = kbuilder.getPackageRegistry(typeDescr.getNamespace()).getPackage().getTypeDeclaration(typeDescr.getTypeName());
try {
if (!type.getTypeClassDef().getFields().isEmpty()) {
//since the declaration defines one or more fields, it is a DEFINITION
type.setNature(TypeDeclaration.Nature.DEFINITION);
} else {
//The declaration doesn't define any field, it is a DECLARATION
type.setNature(TypeDeclaration.Nature.DECLARATION);
}
//if there is no previous declaration, then the original declaration was a POJO
//to the behavior previous these changes
if (previousTypeDeclaration == null) {
// new declarations of a POJO can't declare new fields,
// except if the POJO was previously generated/compiled and saved into the kjar
if (!kbuilder.getBuilderConfiguration().isPreCompiled() &&
!GeneratedFact.class.isAssignableFrom(existingDeclarationClass) && !type.getTypeClassDef().getFields().isEmpty()) {
try {
Class existingClass = pkgRegistry.getPackage().getTypeResolver().resolveType( typeDescr.getType().getFullName() );
ClassFieldInspector cfi = new ClassFieldInspector( existingClass );
int fieldCount = 0;
for ( String existingFieldName : cfi.getFieldTypesField().keySet() ) {
if ( ! cfi.isNonGetter( existingFieldName ) && ! "class".equals( existingFieldName ) && cfi.getSetterMethods().containsKey( existingFieldName ) ) {
if ( ! typeDescr.getFields().containsKey( existingFieldName ) ) {
type.setValid(false);
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, "New declaration of "+typeDescr.getType().getFullName() +
" does not include field " + existingFieldName ) );
} else {
String fldType = cfi.getFieldTypes().get( existingFieldName ).getName();
TypeFieldDescr declaredField = typeDescr.getFields().get( existingFieldName );
if ( ! fldType.equals( type.getTypeClassDef().getField( existingFieldName ).getTypeName() ) ) {
type.setValid(false);
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, "New declaration of "+typeDescr.getType().getFullName() +
" redeclared field " + existingFieldName + " : \n" +
"existing : " + fldType + " vs declared : " + declaredField.getPattern().getObjectType() ) );
} else {
fieldCount++;
}
}
}
}
if ( fieldCount != typeDescr.getFields().size() ) {
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, "New declaration of "+typeDescr.getType().getFullName()
+" can't declaredeclares a different set of fields \n" +
"existing : " + cfi.getFieldTypesField() + "\n" +
"declared : " + typeDescr.getFields() ));
}
} catch ( IOException e ) {
e.printStackTrace();
type.setValid(false);
kbuilder.addBuilderResult( new TypeDeclarationError( typeDescr, "Unable to redeclare " + typeDescr.getType().getFullName() + " : " + e.getMessage() ) );
} catch ( ClassNotFoundException e ) {
type.setValid(false);
kbuilder.addBuilderResult( new TypeDeclarationError( typeDescr, "Unable to redeclare " + typeDescr.getType().getFullName() + " : " + e.getMessage() ) );
}
}
} else {
int typeComparisonResult = this.compareTypeDeclarations(previousTypeDeclaration, type);
if (typeComparisonResult < 0) {
//oldDeclaration is "less" than newDeclaration -> error
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, typeDescr.getType().getFullName()
+ " declares more fields than the already existing version"));
type.setValid(false);
} else if (typeComparisonResult > 0 && !type.getTypeClassDef().getFields().isEmpty()) {
//oldDeclaration is "grater" than newDeclaration -> error
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, typeDescr.getType().getFullName()
+ " declares less fields than the already existing version"));
type.setValid(false);
}
//if they are "equal" -> no problem
// in the case of a declaration, we need to copy all the
// fields present in the previous declaration
if (type.getNature() == TypeDeclaration.Nature.DECLARATION) {
mergeTypeDeclarations(previousTypeDeclaration, type);
}
}
} catch (IncompatibleClassChangeError error) {
//if the types are incompatible -> error
kbuilder.addBuilderResult(new TypeDeclarationError(typeDescr, error.getMessage()));
}
} else {
//if the declaration is novel, then it is a DEFINITION
type.setNature(TypeDeclaration.Nature.DEFINITION);