private boolean mergeTypeDescriptors( AbstractClassTypeDeclarationDescr prev, AbstractClassTypeDeclarationDescr descr) { boolean isDef1 = isDefinition(prev); boolean isDef2 = isDefinition(descr); if (isDef1 && isDef2) { return false; } if (!prev.getSuperTypes().isEmpty() && !descr.getSuperTypes().isEmpty() && prev.getSuperTypes().size() != descr.getSuperTypes().size()) { return false; } if (prev.getSuperTypes().isEmpty()) { for (QualifiedName qn : descr.getSuperTypes()) { ((TypeDeclarationDescr) prev).addSuperType(qn); } } if (prev.getFields().isEmpty()) { for (String fieldName : descr.getFields().keySet()) { prev.addField(descr.getFields().get(fieldName)); } } for (AnnotationDescr ad : descr.getAnnotations()) { prev.addQualifiedAnnotation(ad); } for (AnnotationDescr ad : prev.getAnnotations()) { if (!descr.getAnnotations().contains(ad)) { descr.addQualifiedAnnotation(ad); } } return true; }
private TypeDeclarationError reportDeclarationDiff( ClassFieldInspector cfi, AbstractClassTypeDeclarationDescr typeDescr) { List<String> existing = new ArrayList<String>(); for (String existingFieldName : cfi.getFieldTypesField().keySet()) { if (!cfi.isNonGetter(existingFieldName) && !"class".equals(existingFieldName) && cfi.getSetterMethods().containsKey(existingFieldName)) { existing.add(existingFieldName); } } Collections.sort(existing); List<String> declared = new ArrayList<String>(typeDescr.getFields().keySet()); Collections.sort(declared); List<String> deltas = new ArrayList<String>(); for (String s : existing) { if (!declared.contains(s)) { deltas.add("--" + s); } } for (String s : declared) { if (!existing.contains(s)) { deltas.add("++" + s); } } return new TypeDeclarationError( typeDescr, "New declaration of " + typeDescr.getType().getFullName() + " can't declare a different set of fields \n" + "existing : " + existing + "\n" + "declared : " + declared + "\n" + "diff : " + deltas); }
protected void updateTraitInformation( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type, ClassDefinition def, PackageRegistry pkgRegistry) { if (typeDescr.hasAnnotation(Traitable.class) || (!type.getKind().equals(TypeDeclaration.Kind.TRAIT) && kbuilder.getPackageRegistry().containsKey(def.getSuperClass()) && kbuilder .getPackageRegistry(def.getSuperClass()) .getTraitRegistry() .getTraitables() .containsKey(def.getSuperClass()))) { // traitable if (type.isNovel()) { try { PackageRegistry reg = kbuilder.getPackageRegistry(typeDescr.getNamespace()); String availableName = typeDescr.getType().getFullName(); Class<?> resolvedType = reg.getTypeResolver().resolveType(availableName); updateTraitDefinition(type, resolvedType, false); } catch (ClassNotFoundException cnfe) { // we already know the class exists } } pkgRegistry.getTraitRegistry().addTraitable(def); } else if (type.getKind().equals(TypeDeclaration.Kind.TRAIT) || typeDescr.hasAnnotation(Trait.class)) { // trait if (!type.isNovel()) { try { PackageRegistry reg = kbuilder.getPackageRegistry(typeDescr.getNamespace()); String availableName = typeDescr.getType().getFullName(); Class<?> resolvedType = reg.getTypeResolver().resolveType(availableName); if (!Thing.class.isAssignableFrom(resolvedType)) { if (!resolvedType.isInterface()) { kbuilder.addBuilderResult( new TypeDeclarationError( typeDescr, "Unable to redeclare concrete class " + resolvedType.getName() + " as a trait.")); return; } updateTraitDefinition(type, resolvedType, false); String target = typeDescr.getTypeName() + TraitFactory.SUFFIX; TypeDeclarationDescr tempDescr = new TypeDeclarationDescr(); tempDescr.setNamespace(typeDescr.getNamespace()); tempDescr.setFields(typeDescr.getFields()); tempDescr.setType(target, typeDescr.getNamespace()); tempDescr.setTrait(true); tempDescr.addSuperType(typeDescr.getType()); tempDescr.setResource(type.getResource()); TypeDeclaration tempDeclr = new TypeDeclaration(target); tempDeclr.setKind(TypeDeclaration.Kind.TRAIT); tempDeclr.setTypesafe(type.isTypesafe()); tempDeclr.setNovel(true); tempDeclr.setTypeClassName(tempDescr.getType().getFullName()); tempDeclr.setResource(type.getResource()); ClassDefinition tempDef = new ClassDefinition(target); tempDef.setClassName(tempDescr.getType().getFullName()); tempDef.setTraitable(false); for (FieldDefinition fld : def.getFieldsDefinitions()) { tempDef.addField(fld); } tempDef.setInterfaces(def.getInterfaces()); tempDef.setSuperClass(def.getClassName()); tempDef.setDefinedClass(resolvedType); tempDef.setAbstrakt(true); tempDeclr.setTypeClassDef(tempDef); declaredClassBuilder.generateBeanFromDefinition( tempDescr, tempDeclr, pkgRegistry, tempDef); try { Class<?> clazz = pkgRegistry.getTypeResolver().resolveType(tempDescr.getType().getFullName()); tempDeclr.setTypeClass(clazz); pkgRegistry .getTraitRegistry() .addTrait(tempDef.getClassName().replace(TraitFactory.SUFFIX, ""), tempDef); } catch (ClassNotFoundException cnfe) { kbuilder.addBuilderResult( new TypeDeclarationError( typeDescr, "Internal Trait extension Class '" + target + "' could not be generated correctly'")); } finally { pkgRegistry.getPackage().addTypeDeclaration(tempDeclr); } } else { updateTraitDefinition(type, resolvedType, true); pkgRegistry.getTraitRegistry().addTrait(def); } } catch (ClassNotFoundException cnfe) { // we already know the class exists } } else { if (def.getClassName().endsWith(TraitFactory.SUFFIX)) { pkgRegistry .getTraitRegistry() .addTrait(def.getClassName().replace(TraitFactory.SUFFIX, ""), def); } else { pkgRegistry.getTraitRegistry().addTrait(def); } } } }
private boolean isDefinition(AbstractClassTypeDeclarationDescr prev) { return !prev.getFields().isEmpty(); }
protected void checkRedeclaration( AbstractClassTypeDeclarationDescr typeDescr, TypeDeclaration type, PackageRegistry pkgRegistry) { TypeDeclaration previousTypeDeclaration = kbuilder .getPackageRegistry(typeDescr.getNamespace()) .getPackage() .getTypeDeclaration(typeDescr.getTypeName()); try { // 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 Class<?> existingDeclarationClass = TypeDeclarationUtils.getExistingDeclarationClass(typeDescr, pkgRegistry); 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) && cfi.getGetterMethods().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(); fldType = TypeDeclarationUtils.toBuildableType(fldType, kbuilder.getRootClassLoader()); 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(reportDeclarationDiff(cfi, typeDescr)); } } 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())); } }