protected int compareTypeDeclarations( TypeDeclaration oldDeclaration, TypeDeclaration newDeclaration) throws IncompatibleClassChangeError { // different formats -> incompatible if (!oldDeclaration.getFormat().equals(newDeclaration.getFormat())) { throw new IncompatibleClassChangeError( "Type Declaration " + newDeclaration.getTypeName() + " has a different" + " format that its previous definition: " + newDeclaration.getFormat() + "!=" + oldDeclaration.getFormat()); } // different superclasses -> Incompatible (TODO: check for hierarchy) if (!oldDeclaration .getTypeClassDef() .getSuperClass() .equals(newDeclaration.getTypeClassDef().getSuperClass())) { if (oldDeclaration.getNature() == TypeDeclaration.Nature.DEFINITION && newDeclaration.getNature() == TypeDeclaration.Nature.DECLARATION && Object.class.getName().equals(newDeclaration.getTypeClassDef().getSuperClass())) { // actually do nothing. The new declaration just recalls the previous definition, probably // to extend it. } else { throw new IncompatibleClassChangeError( "Type Declaration " + newDeclaration.getTypeName() + " has a different" + " superclass that its previous definition: " + newDeclaration.getTypeClassDef().getSuperClass() + " != " + oldDeclaration.getTypeClassDef().getSuperClass()); } } // different duration -> Incompatible if (!nullSafeEqualityComparison( oldDeclaration.getDurationAttribute(), newDeclaration.getDurationAttribute())) { throw new IncompatibleClassChangeError( "Type Declaration " + newDeclaration.getTypeName() + " has a different" + " duration: " + newDeclaration.getDurationAttribute() + " != " + oldDeclaration.getDurationAttribute()); } // //different masks -> incompatible if (newDeclaration.getNature().equals(TypeDeclaration.Nature.DEFINITION)) { if (oldDeclaration.getSetMask() != newDeclaration.getSetMask()) { throw new IncompatibleClassChangeError( "Type Declaration " + newDeclaration.getTypeName() + " is incompatible with" + " the previous definition: " + newDeclaration + " != " + oldDeclaration); } } // TODO: further comparison? // Field comparison List<FactField> oldFields = oldDeclaration.getTypeClassDef().getFields(); Map<String, FactField> newFieldsMap = new HashMap<String, FactField>(); for (FactField factField : newDeclaration.getTypeClassDef().getFields()) { newFieldsMap.put(factField.getName(), factField); } // each of the fields in the old definition that are also present in the // new definition must have the same type. If not -> Incompatible boolean allFieldsInOldDeclarationAreStillPresent = true; for (FactField oldFactField : oldFields) { FactField newFactField = newFieldsMap.get(oldFactField.getName()); if (newFactField != null) { // we can't use newFactField.getType() since it throws a NPE at this point. String newFactType = ((FieldDefinition) newFactField).getTypeName(); if (!newFactType.equals(((FieldDefinition) oldFactField).getTypeName())) { throw new IncompatibleClassChangeError( "Type Declaration " + newDeclaration.getTypeName() + "." + newFactField.getName() + " has a different" + " type that its previous definition: " + newFactType + " != " + oldFactField.getType().getCanonicalName()); } } else { allFieldsInOldDeclarationAreStillPresent = false; } } // If the old declaration has less fields than the new declaration, oldDefinition < // newDefinition if (oldFields.size() < newFieldsMap.size()) { return -1; } // If the old declaration has more fields than the new declaration, oldDefinition > // newDefinition if (oldFields.size() > newFieldsMap.size()) { return 1; } // If the old declaration has the same fields as the new declaration, // and all the fieds present in the old declaration are also present in // the new declaration, then they are considered "equal", otherwise // they are incompatible if (allFieldsInOldDeclarationAreStillPresent) { return 0; } // Both declarations have the same number of fields, but not all the // fields in the old declaration are present in the new declaration. throw new IncompatibleClassChangeError( newDeclaration.getTypeName() + " introduces" + " fields that are not present in its previous version."); }