package japicmp.model; import com.google.common.base.Optional; import japicmp.cmp.JarArchiveComparator; import japicmp.util.ClassHelper; import japicmp.util.OptionalHelper; import javassist.CtClass; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlTransient; import java.util.LinkedList; import java.util.List; public class JApiSuperclass implements JApiHasChangeStatus, JApiCompatibility { private final JApiClass jApiClass; private final Optional<CtClass> oldSuperclassOptional; private final Optional<CtClass> newSuperclassOptional; private final JApiChangeStatus changeStatus; private final JarArchiveComparator jarArchiveComparator; private final List<JApiCompatibilityChange> compatibilityChanges = new LinkedList<>(); private Optional<JApiClass> correspondingJApiClass = Optional.absent(); public JApiSuperclass(JApiClass jApiClass, Optional<CtClass> oldSuperclassOptional, Optional<CtClass> newSuperclassOptional, JApiChangeStatus changeStatus, JarArchiveComparator jarArchiveComparator) { this.jApiClass = jApiClass; this.oldSuperclassOptional = oldSuperclassOptional; this.newSuperclassOptional = newSuperclassOptional; this.changeStatus = changeStatus; this.jarArchiveComparator = jarArchiveComparator; } /** * Returns the {@link japicmp.model.JApiClass} representation of this superclass. * The return value is Optional.absent() in case the superclass for the old and new version is absent. * * @return the {@link japicmp.model.JApiClass} representation of this superclass as {@link com.google.common.base.Optional} */ public Optional<JApiClass> getJApiClass() { if (oldSuperclassOptional.isPresent() && newSuperclassOptional.isPresent()) { CtClass oldSuperclass = oldSuperclassOptional.get(); CtClass newSuperclass = newSuperclassOptional.get(); String oldSuperclassName = oldSuperclass.getName(); String newSuperclassName = newSuperclass.getName(); if (oldSuperclassName.equals(newSuperclassName)) { JApiClassType classType = new JApiClassType(Optional.of(ClassHelper.getType(oldSuperclass)), Optional.of(ClassHelper.getType(newSuperclass)), JApiChangeStatus.UNCHANGED); JApiClass jApiClass = new JApiClass(jarArchiveComparator, oldSuperclassName, Optional.of(oldSuperclass), Optional.of(newSuperclass), JApiChangeStatus.UNCHANGED, classType); return Optional.of(jApiClass); } else { return Optional.absent(); } } else if (oldSuperclassOptional.isPresent()) { CtClass oldSuperclass = oldSuperclassOptional.get(); String oldSuperclassName = oldSuperclass.getName(); JApiClassType classType = new JApiClassType(Optional.of(ClassHelper.getType(oldSuperclass)), Optional.<JApiClassType.ClassType>absent(), JApiChangeStatus.REMOVED); JApiClass jApiClass = new JApiClass(jarArchiveComparator, oldSuperclassName, Optional.of(oldSuperclass), Optional.<CtClass>absent(), JApiChangeStatus.REMOVED, classType); return Optional.of(jApiClass); } else if (newSuperclassOptional.isPresent()) { CtClass newSuperclass = newSuperclassOptional.get(); String newSuperclassName = newSuperclass.getName(); JApiClassType classType = new JApiClassType(Optional.<JApiClassType.ClassType>absent(), Optional.of(ClassHelper.getType(newSuperclass)), JApiChangeStatus.NEW); JApiClass jApiClass = new JApiClass(jarArchiveComparator, newSuperclassName, Optional.<CtClass>absent(), Optional.of(newSuperclass), JApiChangeStatus.NEW, classType); return Optional.of(jApiClass); } return Optional.absent(); } @XmlTransient public Optional<CtClass> getOldSuperclass() { return oldSuperclassOptional; } @XmlTransient public Optional<CtClass> getNewSuperclass() { return newSuperclassOptional; } @XmlTransient public Optional<String> getOldSuperclassName() { return oldSuperclassOptional.isPresent() ? Optional.of(oldSuperclassOptional.get().getName()) : Optional.<String>absent(); } @XmlTransient public Optional<String> getNewSuperclassName() { return newSuperclassOptional.isPresent() ? Optional.of(newSuperclassOptional.get().getName()) : Optional.<String>absent(); } @XmlAttribute(name = "changeStatus") public JApiChangeStatus getChangeStatus() { return changeStatus; } @XmlAttribute(name = "superclassOld") public String getSuperclassOld() { return OptionalHelper.optionalToString(getOldSuperclassName()); } @XmlAttribute(name = "superclassNew") public String getSuperclassNew() { return OptionalHelper.optionalToString(getNewSuperclassName()); } @Override @XmlAttribute public boolean isBinaryCompatible() { boolean binaryCompatible = true; for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) { if (!compatibilityChange.isBinaryCompatible()) { binaryCompatible = false; } } return binaryCompatible; } @Override @XmlAttribute public boolean isSourceCompatible() { boolean sourceCompatible = true; for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) { if (!compatibilityChange.isSourceCompatible()) { sourceCompatible = false; } } return sourceCompatible; } @XmlElementWrapper(name = "compatibilityChanges") @XmlElement(name = "compatibilityChange") public List<JApiCompatibilityChange> getCompatibilityChanges() { return this.compatibilityChanges; } void setJApiClass(JApiClass jApiClass) { this.correspondingJApiClass = Optional.of(jApiClass); } /** * Returns the {@link japicmp.model.JApiClass} this superclass belongs to. * @return the JApiClass this superclass belongs to. */ @XmlTransient public JApiClass getJApiClassOwning() { return jApiClass; } }