From c714666c0f4e19bb9db163f576e28d36cad7df74 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 3 Apr 2015 05:00:00 +0200 Subject: Add Delta.CompatChange for binary compatible changes, i.e. change in method throws clause or final field value Change in method throws clause: - Tools.isThrowsClauseChange(..) - Change of final field value: - Tools.isFieldValueChange(..) - --- .../java/org/osjava/jardiff/DOMDiffHandler.java | 274 +++++++++++++-------- .../main/java/org/osjava/jardiff/DiffCriteria.java | 28 ++- .../main/java/org/osjava/jardiff/DiffHandler.java | 56 +++-- api/src/main/java/org/osjava/jardiff/JarDiff.java | 192 ++++++++------- .../org/osjava/jardiff/PublicDiffCriteria.java | 61 +++-- .../org/osjava/jardiff/SimpleDiffCriteria.java | 61 +++-- .../java/org/osjava/jardiff/StreamDiffHandler.java | 239 +++++++++++------- api/src/main/java/org/osjava/jardiff/Tools.java | 64 ++++- api/src/main/java/org/semver/Delta.java | 20 +- api/src/main/java/org/semver/Dumper.java | 93 +++++-- .../jardiff/DifferenceAccumulatingHandler.java | 19 ++ 11 files changed, 727 insertions(+), 380 deletions(-) (limited to 'api') diff --git a/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java b/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java index a05bbbf..64eef26 100644 --- a/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java +++ b/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java @@ -16,7 +16,7 @@ */ package org.osjava.jardiff; -/* Not in 1.4.2 +/* Not in 1.4.2 import javax.xml.XMLConstants; */ import javax.xml.parsers.DocumentBuilderFactory; @@ -66,7 +66,7 @@ public class DOMDiffHandler implements DiffHandler * The current Node. */ private Node currentNode; - + /** * Create a new DOMDiffHandler which writes to System.out * @@ -75,21 +75,21 @@ public class DOMDiffHandler implements DiffHandler */ public DOMDiffHandler() throws DiffException { try { - TransformerFactory tf = TransformerFactory.newInstance(); + final TransformerFactory tf = TransformerFactory.newInstance(); this.transformer = tf.newTransformer(); this.result = new StreamResult(System.out); this.currentNode = null; - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); - DocumentBuilder db = dbf.newDocumentBuilder(); + final DocumentBuilder db = dbf.newDocumentBuilder(); this.doc = db.newDocument(); - } catch (TransformerConfigurationException tce) { + } catch (final TransformerConfigurationException tce) { throw new DiffException(tce); - } catch (ParserConfigurationException pce) { + } catch (final ParserConfigurationException pce) { throw new DiffException(pce); } } - + /** * Create a new DOMDiffHandler with the specified Transformer and Result. * This method allows the user to choose what they are going to do with @@ -99,22 +99,22 @@ public class DOMDiffHandler implements DiffHandler * @param transformer The transformer to transform the output with. * @param result Where to put the result. */ - public DOMDiffHandler(Transformer transformer, Result result) + public DOMDiffHandler(final Transformer transformer, final Result result) throws DiffException { try { this.transformer = transformer; this.result = result; this.currentNode = null; - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); - DocumentBuilder db = dbf.newDocumentBuilder(); + final DocumentBuilder db = dbf.newDocumentBuilder(); this.doc = db.newDocument(); - } catch (ParserConfigurationException pce) { + } catch (final ParserConfigurationException pce) { throw new DiffException(pce); } } - + /** * Start the diff. * This writes out the start of a <diff> node. @@ -124,8 +124,8 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void startDiff(String oldJar, String newJar) throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "diff"); + public void startDiff(final String oldJar, final String newJar) throws DiffException { + final Element tmp = doc.createElementNS(XML_URI, "diff"); tmp.setAttribute( "old", oldJar); tmp.setAttribute( "new", newJar); doc.appendChild(tmp); @@ -139,7 +139,7 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void startOldContents() throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "oldcontents"); + final Element tmp = doc.createElementNS(XML_URI, "oldcontents"); currentNode.appendChild(tmp); currentNode = tmp; } @@ -151,7 +151,7 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void startNewContents() throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "newcontents"); + final Element tmp = doc.createElementNS(XML_URI, "newcontents"); currentNode.appendChild(tmp); currentNode = tmp; } @@ -163,8 +163,8 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void contains(ClassInfo info) throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "class"); + public void contains(final ClassInfo info) throws DiffException { + final Element tmp = doc.createElementNS(XML_URI, "class"); tmp.setAttribute("name", info.getName()); currentNode.appendChild(tmp); } @@ -188,7 +188,7 @@ public class DOMDiffHandler implements DiffHandler public void endNewContents() throws DiffException { currentNode = currentNode.getParentNode(); } - + /** * Start the removed node. * This writes out a <removed> node. @@ -197,11 +197,11 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void startRemoved() throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "removed"); + final Element tmp = doc.createElementNS(XML_URI, "removed"); currentNode.appendChild(tmp); currentNode = tmp; } - + /** * Write out class info for a removed class. * This writes out the nodes describing a class @@ -210,10 +210,10 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classRemoved(ClassInfo info) throws DiffException { + public void classRemoved(final ClassInfo info) throws DiffException { writeClassInfo(info); } - + /** * End the removed section. * This closes the <removed> tag. @@ -224,7 +224,7 @@ public class DOMDiffHandler implements DiffHandler public void endRemoved() throws DiffException { currentNode = currentNode.getParentNode(); } - + /** * Start the added section. * This opens the <added> tag. @@ -233,11 +233,11 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void startAdded() throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "added"); + final Element tmp = doc.createElementNS(XML_URI, "added"); currentNode.appendChild(tmp); currentNode = tmp; } - + /** * Write out the class info for an added class. * This writes out the nodes describing an added class. @@ -246,10 +246,10 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classAdded(ClassInfo info) throws DiffException { + public void classAdded(final ClassInfo info) throws DiffException { writeClassInfo(info); } - + /** * End the added section. * This closes the <added> tag. @@ -260,7 +260,7 @@ public class DOMDiffHandler implements DiffHandler public void endAdded() throws DiffException { currentNode = currentNode.getParentNode(); } - + /** * Start the changed section. * This writes out the <changed> node. @@ -269,11 +269,11 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void startChanged() throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "changed"); + final Element tmp = doc.createElementNS(XML_URI, "changed"); currentNode.appendChild(tmp); currentNode = tmp; } - + /** * Start a changed section for an individual class. * This writes out an <classchanged> node with the real class @@ -283,14 +283,14 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void startClassChanged(String internalName) throws DiffException + public void startClassChanged(final String internalName) throws DiffException { - Element tmp = doc.createElementNS(XML_URI, "classchanged"); + final Element tmp = doc.createElementNS(XML_URI, "classchanged"); tmp.setAttribute( "name", internalName); currentNode.appendChild(tmp); currentNode = tmp; } - + /** * Write out info about a removed field. * This just writes out the field info, it will be inside a start/end @@ -300,36 +300,36 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldRemoved(FieldInfo info) throws DiffException { + public void fieldRemoved(final FieldInfo info) throws DiffException { writeFieldInfo(info); } - + /** * Write out info about a removed method. - * This just writes out the method info, it will be inside a start/end + * This just writes out the method info, it will be inside a start/end * removed section. * * @param info Info about the method that's been removed. * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodRemoved(MethodInfo info) throws DiffException { + public void methodRemoved(final MethodInfo info) throws DiffException { writeMethodInfo(info); } - + /** * Write out info about an added field. - * This just writes out the field info, it will be inside a start/end + * This just writes out the field info, it will be inside a start/end * added section. * * @param info Info about the added field. * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldAdded(FieldInfo info) throws DiffException { + public void fieldAdded(final FieldInfo info) throws DiffException { writeFieldInfo(info); } - + /** * Write out info about a added method. * This just writes out the method info, it will be inside a start/end @@ -339,13 +339,13 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodAdded(MethodInfo info) throws DiffException { + public void methodAdded(final MethodInfo info) throws DiffException { writeMethodInfo(info); } - + /** * Write out info aboout a changed class. - * This writes out a <classchange> node, followed by a + * This writes out a <classchange> node, followed by a * <from> node, with the old information about the class * followed by a <to> node with the new information about the * class. @@ -355,13 +355,13 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classChanged(ClassInfo oldInfo, ClassInfo newInfo) - throws DiffException + public void classChanged(final ClassInfo oldInfo, final ClassInfo newInfo) + throws DiffException { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "classchange"); - Element from = doc.createElementNS(XML_URI, "from"); - Element to = doc.createElementNS(XML_URI, "to"); + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "classchange"); + final Element from = doc.createElementNS(XML_URI, "from"); + final Element to = doc.createElementNS(XML_URI, "to"); tmp.appendChild(from); tmp.appendChild(to); currentNode.appendChild(tmp); @@ -371,11 +371,11 @@ public class DOMDiffHandler implements DiffHandler writeClassInfo(newInfo); this.currentNode = currentNode; } - + /** * Invokes {@link #classChanged(ClassInfo, ClassInfo)}. */ - public void classDeprecated(ClassInfo oldInfo, ClassInfo newInfo) + public void classDeprecated(final ClassInfo oldInfo, final ClassInfo newInfo) throws DiffException { classChanged(oldInfo, newInfo); @@ -383,7 +383,36 @@ public class DOMDiffHandler implements DiffHandler /** * Write out info aboout a changed field. - * This writes out a <fieldchange> node, followed by a + * This writes out a <fieldchange> node, followed by a + * <from> node, with the old information about the field + * followed by a <to> node with the new information about the + * field. + * + * @param oldInfo Info about the old field. + * @param newInfo Info about the new field. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void fieldChanged(final FieldInfo oldInfo, final FieldInfo newInfo) + throws DiffException + { + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "fieldchange"); + final Element from = doc.createElementNS(XML_URI, "from"); + final Element to = doc.createElementNS(XML_URI, "to"); + tmp.appendChild(from); + tmp.appendChild(to); + currentNode.appendChild(tmp); + this.currentNode = from; + writeFieldInfo(oldInfo); + this.currentNode = to; + writeFieldInfo(newInfo); + this.currentNode = currentNode; + } + + /** + * Write out info about a binary compatible changed field. + * This writes out a <fieldchangecompat> node, followed by a * <from> node, with the old information about the field * followed by a <to> node with the new information about the * field. @@ -393,13 +422,13 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldChanged(FieldInfo oldInfo, FieldInfo newInfo) - throws DiffException + public void fieldChangedCompat(final FieldInfo oldInfo, final FieldInfo newInfo) + throws DiffException { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "fieldchange"); - Element from = doc.createElementNS(XML_URI, "from"); - Element to = doc.createElementNS(XML_URI, "to"); + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "fieldchangecompat"); + final Element from = doc.createElementNS(XML_URI, "from"); + final Element to = doc.createElementNS(XML_URI, "to"); tmp.appendChild(from); tmp.appendChild(to); currentNode.appendChild(tmp); @@ -409,18 +438,18 @@ public class DOMDiffHandler implements DiffHandler writeFieldInfo(newInfo); this.currentNode = currentNode; } - + /** * Invokes {@link #fieldChanged(FieldInfo, FieldInfo)}. */ - public void fieldDeprecated(FieldInfo oldInfo, FieldInfo newInfo) + public void fieldDeprecated(final FieldInfo oldInfo, final FieldInfo newInfo) throws DiffException { fieldChanged(oldInfo, newInfo); } /** - * Write out info aboout a changed method. - * This writes out a <methodchange> node, followed by a + * Write out info about a changed method. + * This writes out a <methodchange> node, followed by a * <from> node, with the old information about the method * followed by a <to> node with the new information about the * method. @@ -430,13 +459,40 @@ public class DOMDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodChanged(MethodInfo oldInfo, MethodInfo newInfo) + public void methodChanged(final MethodInfo oldInfo, final MethodInfo newInfo) throws DiffException { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "methodchange"); - Element from = doc.createElementNS(XML_URI, "from"); - Element to = doc.createElementNS(XML_URI, "to"); + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "methodchange"); + final Element from = doc.createElementNS(XML_URI, "from"); + final Element to = doc.createElementNS(XML_URI, "to"); + tmp.appendChild(from); + tmp.appendChild(to); + currentNode.appendChild(tmp); + this.currentNode = from; + writeMethodInfo(oldInfo); + this.currentNode = to; + writeMethodInfo(newInfo); + this.currentNode = currentNode; + } + + /** + * Write out info about a binary compatible changed method. + * This writes out a <methodchangecompat> node, followed by a + * <from> node, with the old information about the method + * followed by a <to> node with the new information about the + * method. + * + * @param oldInfo Info about the old method. + * @param newInfo Info about the new method. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void methodChangedCompat(final MethodInfo oldInfo, final MethodInfo newInfo) throws DiffException { + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "methodchangecompat"); + final Element from = doc.createElementNS(XML_URI, "from"); + final Element to = doc.createElementNS(XML_URI, "to"); tmp.appendChild(from); tmp.appendChild(to); currentNode.appendChild(tmp); @@ -446,11 +502,11 @@ public class DOMDiffHandler implements DiffHandler writeMethodInfo(newInfo); this.currentNode = currentNode; } - + /** * Invokes {@link #methodChanged(MethodInfo, MethodInfo)}. */ - public void methodDeprecated(MethodInfo oldInfo, MethodInfo newInfo) + public void methodDeprecated(final MethodInfo oldInfo, final MethodInfo newInfo) throws DiffException { methodChanged(oldInfo, newInfo); @@ -466,7 +522,7 @@ public class DOMDiffHandler implements DiffHandler public void endClassChanged() throws DiffException { currentNode = currentNode.getParentNode(); } - + /** * End the changed section. * This closes the <changed> node. @@ -477,7 +533,7 @@ public class DOMDiffHandler implements DiffHandler public void endChanged() throws DiffException { currentNode = currentNode.getParentNode(); } - + /** * End the diff. * This closes the <diff> node. @@ -486,14 +542,14 @@ public class DOMDiffHandler implements DiffHandler * writing to a file caused an IOException */ public void endDiff() throws DiffException { - DOMSource source = new DOMSource(doc); + final DOMSource source = new DOMSource(doc); try { transformer.transform(source, result); - } catch (TransformerException te) { + } catch (final TransformerException te) { throw new DiffException(te); } } - + /** * Write out information about a class. * This writes out a <class> node, which contains information about @@ -501,9 +557,9 @@ public class DOMDiffHandler implements DiffHandler * * @param info Info about the class to write out. */ - protected void writeClassInfo(ClassInfo info) { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "class"); + protected void writeClassInfo(final ClassInfo info) { + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "class"); currentNode.appendChild(tmp); this.currentNode = tmp; addAccessFlags(info); @@ -516,27 +572,27 @@ public class DOMDiffHandler implements DiffHandler if (info.getSupername() != null) tmp.setAttribute( "superclass", info.getSupername()); - String[] interfaces = info.getInterfaces(); + final String[] interfaces = info.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { - Element iface = doc.createElementNS(XML_URI, "implements"); + final Element iface = doc.createElementNS(XML_URI, "implements"); tmp.appendChild(iface); - iface.setAttribute( "name", + iface.setAttribute( "name", interfaces[i]); } this.currentNode = currentNode; } - + /** * Write out information about a method. * This writes out a <method> node which contains information about - * the arguments, the return type, and the exceptions thrown by the + * the arguments, the return type, and the exceptions thrown by the * method. * * @param info Info about the method. */ - protected void writeMethodInfo(MethodInfo info) { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "method"); + protected void writeMethodInfo(final MethodInfo info) { + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "method"); currentNode.appendChild(tmp); this.currentNode = tmp; addAccessFlags(info); @@ -547,17 +603,17 @@ public class DOMDiffHandler implements DiffHandler tmp.setAttribute( "signature", info.getSignature()); if (info.getDesc() != null) addMethodNodes(info.getDesc()); - String[] exceptions = info.getExceptions(); + final String[] exceptions = info.getExceptions(); if (exceptions != null) { for (int i = 0; i < exceptions.length; i++) { - Element excep = doc.createElementNS(XML_URI, "exception"); + final Element excep = doc.createElementNS(XML_URI, "exception"); excep.setAttribute( "name", exceptions[i]); tmp.appendChild(excep); } } this.currentNode = currentNode; } - + /** * Write out information about a field. * This writes out a <field> node with attributes describing the @@ -565,18 +621,18 @@ public class DOMDiffHandler implements DiffHandler * * @param info Info about the field. */ - protected void writeFieldInfo(FieldInfo info) { - Node currentNode = this.currentNode; - Element tmp = doc.createElementNS(XML_URI, "field"); + protected void writeFieldInfo(final FieldInfo info) { + final Node currentNode = this.currentNode; + final Element tmp = doc.createElementNS(XML_URI, "field"); currentNode.appendChild(tmp); this.currentNode = tmp; addAccessFlags(info); if (info.getName() != null) - tmp.setAttribute( "name", + tmp.setAttribute( "name", info.getName()); if (info.getSignature() != null) - tmp.setAttribute( "signature", + tmp.setAttribute( "signature", info.getSignature()); if (info.getValue() != null) tmp.setAttribute( "value", @@ -585,7 +641,7 @@ public class DOMDiffHandler implements DiffHandler addTypeNode(info.getDesc()); this.currentNode = currentNode; } - + /** * Add attributes describing some access flags. * This adds the attributes to the attr field. @@ -593,8 +649,8 @@ public class DOMDiffHandler implements DiffHandler * @see #attr * @param info Info describing the access flags. */ - protected void addAccessFlags(AbstractInfo info) { - Element currentNode = (Element) this.currentNode; + protected void addAccessFlags(final AbstractInfo info) { + final Element currentNode = (Element) this.currentNode; currentNode.setAttribute( "access", info.getAccessType()); if (info.isAbstract()) currentNode.setAttribute( "abstract", "yes"); @@ -629,19 +685,19 @@ public class DOMDiffHandler implements DiffHandler if (info.isVolatile()) currentNode.setAttribute( "volatile", "yes"); } - + /** * Add the method nodes for the method descriptor. - * This writes out an <arguments> node containing the + * This writes out an <arguments> node containing the * argument types for the method, followed by a <return> node * containing the return type. * * @param desc The descriptor for the method to write out. */ - protected void addMethodNodes(String desc) { - Type[] args = Type.getArgumentTypes(desc); - Type ret = Type.getReturnType(desc); - Node currentNode = this.currentNode; + protected void addMethodNodes(final String desc) { + final Type[] args = Type.getArgumentTypes(desc); + final Type ret = Type.getReturnType(desc); + final Node currentNode = this.currentNode; Element tmp = doc.createElementNS(XML_URI,"arguments"); currentNode.appendChild(tmp); this.currentNode = tmp; @@ -653,16 +709,16 @@ public class DOMDiffHandler implements DiffHandler addTypeNode(ret); this.currentNode = currentNode; } - + /** * Add a type node for the specified descriptor. * * @param desc A type descriptor. */ - protected void addTypeNode(String desc) { + protected void addTypeNode(final String desc) { addTypeNode(Type.getType(desc)); } - + /** * Add a type node for the specified type. * This writes out a <type> node with attributes describing @@ -671,7 +727,7 @@ public class DOMDiffHandler implements DiffHandler * @param type The type to describe. */ protected void addTypeNode(Type type) { - Element tmp = doc.createElementNS(XML_URI, "type"); + final Element tmp = doc.createElementNS(XML_URI, "type"); currentNode.appendChild(tmp); int i = type.getSort(); if (i == Type.ARRAY) { diff --git a/api/src/main/java/org/osjava/jardiff/DiffCriteria.java b/api/src/main/java/org/osjava/jardiff/DiffCriteria.java index 123f1a2..e40d939 100644 --- a/api/src/main/java/org/osjava/jardiff/DiffCriteria.java +++ b/api/src/main/java/org/osjava/jardiff/DiffCriteria.java @@ -29,29 +29,29 @@ public interface DiffCriteria * @return true if classinfo is interesting, false otherwise. */ public boolean validClass(ClassInfo classinfo); - + /** * Check if the method described by methodinfo is interesting. * * @return true if methodinfo is interesting, false otherwise. */ public boolean validMethod(MethodInfo methodinfo); - + /** * Check if the method described by fieldinfo is interesting. * * @return true if fieldinfo is interesting, false otherwise. */ public boolean validField(FieldInfo fieldinfo); - + /** - * Check if the differences between the class described by infoA and + * Check if the differences between the class described by infoA and * the class described by infoB are interesting. * * @return true if the changes are interesting, false otherwise. */ public boolean differs(ClassInfo infoA, ClassInfo infoB); - + /** * Check if the differences between the method described by infoA and * the method described by infoB are interesting. @@ -59,7 +59,15 @@ public interface DiffCriteria * @return true if the changes are interesting, false otherwise. */ public boolean differs(MethodInfo methodinfo, MethodInfo methodinfo_1_); - + + /** + * Check if the differences between the method described by infoA and + * the method described by infoB are binary incompatible. + * + * @return true if the changes are interesting, false otherwise. + */ + public boolean differsBinary(MethodInfo methodinfo, MethodInfo methodinfo_1_); + /** * Check if the differences between the field described by infoA and the * field described by infoB are interesting. @@ -67,4 +75,12 @@ public interface DiffCriteria * @return true if the changes are interesting, false otherwise. */ public boolean differs(FieldInfo fieldinfo, FieldInfo fieldinfo_2_); + + /** + * Check if the differences between the field described by infoA and the + * field described by infoB are binary incompatible. + * + * @return true if the changes are interesting, false otherwise. + */ + public boolean differsBinary(FieldInfo fieldinfo, FieldInfo fieldinfo_2_); } diff --git a/api/src/main/java/org/osjava/jardiff/DiffHandler.java b/api/src/main/java/org/osjava/jardiff/DiffHandler.java index e10f1bf..285f0d3 100644 --- a/api/src/main/java/org/osjava/jardiff/DiffHandler.java +++ b/api/src/main/java/org/osjava/jardiff/DiffHandler.java @@ -28,7 +28,7 @@ public interface DiffHandler /** * Start a diff between two versions, where string a is the old version * and string b is the new version. - * + * * @param a the name of the old version * @param b the name of the new version * @throws DiffException when there is an underlying exception, e.g. @@ -85,7 +85,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void startRemoved() throws DiffException; - + /** * Notification that a class was removed. * @@ -94,7 +94,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void classRemoved(ClassInfo classinfo) throws DiffException; - + /** * End of list of removed classes. * @@ -102,7 +102,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void endRemoved() throws DiffException; - + /** * Start of list of added classes. * @@ -110,7 +110,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void startAdded() throws DiffException; - + /** * Notification that a class was added. * @@ -119,7 +119,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void classAdded(ClassInfo classinfo) throws DiffException; - + /** * End of list of removed classes. * @@ -127,7 +127,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void endAdded() throws DiffException; - + /** * Start list of changed classes. * @@ -135,7 +135,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void startChanged() throws DiffException; - + /** * Start information about class changes for the classname passed. * @@ -143,7 +143,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void startClassChanged(String string) throws DiffException; - + /** * The field was removed for the current class that has changed. * @@ -152,7 +152,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void fieldRemoved(FieldInfo fieldinfo) throws DiffException; - + /** * The method was removed for the current class that has changed. * @@ -161,7 +161,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void methodRemoved(MethodInfo methodinfo) throws DiffException; - + /** * The field was added for the current class that has changed. * @@ -170,7 +170,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void fieldAdded(FieldInfo fieldinfo) throws DiffException; - + /** * The method was added for the current class that has changed. * @@ -179,7 +179,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void methodAdded(MethodInfo methodinfo) throws DiffException; - + /** * The current class has changed. * This is called when a class's interfaces or superclass or access @@ -192,7 +192,7 @@ public interface DiffHandler */ public void classChanged(ClassInfo oldClassinfo, ClassInfo newClassinfo) throws DiffException; - + /** * The current class has been deprecated. * @@ -214,7 +214,18 @@ public interface DiffHandler */ public void fieldChanged(FieldInfo oldFieldinfo, FieldInfo newFieldinfo) throws DiffException; - + + /** + * A field on the current class has changed in a binary compatible manner. + * + * @param oldFieldinfo Information about the old field. + * @param newFieldinfo Information about the new field. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void fieldChangedCompat(FieldInfo oldFieldinfo, FieldInfo newFieldinfo) + throws DiffException; + /** * A field on the current class has been deprecated. * @@ -237,6 +248,17 @@ public interface DiffHandler public void methodChanged (MethodInfo oldMethodInfo, MethodInfo newMethodInfo) throws DiffException; + /** + * A method on the current class has changed in a binary compatible manner. + * + * @param oldMethodInfo Information about the old method. + * @param newMethodInfo Information about the new method. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void methodChangedCompat + (MethodInfo oldMethodInfo, MethodInfo newMethodInfo) throws DiffException; + /** * The method has been deprecated. * @@ -255,7 +277,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void endClassChanged() throws DiffException; - + /** * End of class changes. * @@ -263,7 +285,7 @@ public interface DiffHandler * writing to a file caused an IOException */ public void endChanged() throws DiffException; - + /** * End of the diff. * diff --git a/api/src/main/java/org/osjava/jardiff/JarDiff.java b/api/src/main/java/org/osjava/jardiff/JarDiff.java index 24d92ff..e7d6429 100644 --- a/api/src/main/java/org/osjava/jardiff/JarDiff.java +++ b/api/src/main/java/org/osjava/jardiff/JarDiff.java @@ -88,7 +88,7 @@ public class JarDiff /** * Class info visitor, used to load information about classes. */ - private ClassInfoVisitor infoVisitor = new ClassInfoVisitor(); + private final ClassInfoVisitor infoVisitor = new ClassInfoVisitor(); /** * Create a new JarDiff object. @@ -101,7 +101,7 @@ public class JarDiff * * @param oldVersion the name */ - public void setOldVersion(String oldVersion) { + public void setOldVersion(final String oldVersion) { this.oldVersion = oldVersion; } @@ -119,7 +119,7 @@ public class JarDiff * * @param newVersion the version */ - public void setNewVersion(String newVersion) { + public void setNewVersion(final String newVersion) { this.newVersion = newVersion; } @@ -138,7 +138,7 @@ public class JarDiff * @param deps an array of urls pointing to jar files or directories * containing classes which are required dependencies. */ - public void setDependencies(URL[] deps) { + public void setDependencies(final URL[] deps) { this.deps = deps; } @@ -157,7 +157,7 @@ public class JarDiff * @param reader the ClassReader * @return the ClassInfo */ - public synchronized ClassInfo loadClassInfo(ClassReader reader) + public synchronized ClassInfo loadClassInfo(final ClassReader reader) throws IOException { infoVisitor.reset(); @@ -175,7 +175,7 @@ public class JarDiff * @throws DiffException if there is an exception reading info about a * class. */ - private void loadClasses(Map infoMap, URL path) throws DiffException { + private void loadClasses(final Map infoMap, final URL path) throws DiffException { try { File jarFile = null; if(!"file".equals(path.getProtocol()) || path.getHost() != null) { @@ -184,9 +184,9 @@ public class JarDiff jarFile = File.createTempFile("jardiff","jar"); // Mark it to be deleted on exit. jarFile.deleteOnExit(); - InputStream in = path.openStream(); - OutputStream out = new FileOutputStream(jarFile); - byte[] buffer = new byte[4096]; + final InputStream in = path.openStream(); + final OutputStream out = new FileOutputStream(jarFile); + final byte[] buffer = new byte[4096]; int i; while( (i = in.read(buffer,0,buffer.length)) != -1) { out.write(buffer, 0, i); @@ -198,7 +198,7 @@ public class JarDiff jarFile = new File(path.getPath()); } loadClasses(infoMap, jarFile); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -214,21 +214,21 @@ public class JarDiff * @throws IOException if there is an IOException reading info about a * class. */ - private void loadClasses(Map infoMap, File file) throws DiffException { + private void loadClasses(final Map infoMap, final File file) throws DiffException { try { - JarFile jar = new JarFile(file); - Enumeration e = jar.entries(); + final JarFile jar = new JarFile(file); + final Enumeration e = jar.entries(); while (e.hasMoreElements()) { - JarEntry entry = (JarEntry) e.nextElement(); - String name = entry.getName(); + final JarEntry entry = (JarEntry) e.nextElement(); + final String name = entry.getName(); if (!entry.isDirectory() && name.endsWith(".class")) { - ClassReader reader + final ClassReader reader = new ClassReader(jar.getInputStream(entry)); - ClassInfo ci = loadClassInfo(reader); + final ClassInfo ci = loadClassInfo(reader); infoMap.put(ci.getName(), ci); } } - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -239,7 +239,7 @@ public class JarDiff * @param loc The location of a jar file to load classes from. * @throws DiffException if there is an IOException. */ - public void loadOldClasses(URL loc) throws DiffException { + public void loadOldClasses(final URL loc) throws DiffException { loadClasses(oldClassInfo, loc); } @@ -249,7 +249,7 @@ public class JarDiff * @param loc The location of a jar file to load classes from. * @throws DiffException if there is an IOException. */ - public void loadNewClasses(URL loc) throws DiffException { + public void loadNewClasses(final URL loc) throws DiffException { loadClasses(newClassInfo, loc); } @@ -259,7 +259,7 @@ public class JarDiff * @param file The location of a jar file to load classes from. * @throws DiffException if there is an IOException */ - public void loadOldClasses(File file) throws DiffException { + public void loadOldClasses(final File file) throws DiffException { loadClasses(oldClassInfo, file); } @@ -269,7 +269,7 @@ public class JarDiff * @param file The location of a jar file to load classes from. * @throws DiffException if there is an IOException */ - public void loadNewClasses(File file) throws DiffException { + public void loadNewClasses(final File file) throws DiffException { loadClasses(newClassInfo, file); } @@ -282,21 +282,21 @@ public class JarDiff * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void diff(DiffHandler handler, DiffCriteria criteria) + public void diff(final DiffHandler handler, final DiffCriteria criteria) throws DiffException { diff(handler, criteria, oldVersion, newVersion, oldClassInfo, newClassInfo); } - public void diff(DiffHandler handler, DiffCriteria criteria, - String oldVersion, String newVersion, - Map oldClassInfo, Map newClassInfo) throws DiffException + public void diff(final DiffHandler handler, final DiffCriteria criteria, + final String oldVersion, final String newVersion, + final Map oldClassInfo, final Map newClassInfo) throws DiffException { // TODO: Build the name from the MANIFEST rather than the filename handler.startDiff(oldVersion, newVersion); handler.startOldContents(); - for (ClassInfo ci : oldClassInfo.values()) { + for (final ClassInfo ci : oldClassInfo.values()) { if (criteria.validClass(ci)) { handler.contains(ci); } @@ -304,23 +304,23 @@ public class JarDiff handler.endOldContents(); handler.startNewContents(); - for (ClassInfo ci : newClassInfo.values()) { + for (final ClassInfo ci : newClassInfo.values()) { if (criteria.validClass(ci)) { handler.contains(ci); } } handler.endNewContents(); - Set onlyOld = new TreeSet(oldClassInfo.keySet()); - Set onlyNew = new TreeSet(newClassInfo.keySet()); - Set both = new TreeSet(oldClassInfo.keySet()); + final Set onlyOld = new TreeSet(oldClassInfo.keySet()); + final Set onlyNew = new TreeSet(newClassInfo.keySet()); + final Set both = new TreeSet(oldClassInfo.keySet()); onlyOld.removeAll(newClassInfo.keySet()); onlyNew.removeAll(oldClassInfo.keySet()); both.retainAll(newClassInfo.keySet()); handler.startRemoved(); - for (String s : onlyOld) { - ClassInfo ci = oldClassInfo.get(s); + for (final String s : onlyOld) { + final ClassInfo ci = oldClassInfo.get(s); if (criteria.validClass(ci)) { handler.classRemoved(ci); } @@ -328,44 +328,44 @@ public class JarDiff handler.endRemoved(); handler.startAdded(); - for (String s : onlyNew) { - ClassInfo ci = newClassInfo.get(s); + for (final String s : onlyNew) { + final ClassInfo ci = newClassInfo.get(s); if (criteria.validClass(ci)) { handler.classAdded(ci); } } handler.endAdded(); - Set removedMethods = new TreeSet(); - Set removedFields = new TreeSet(); - Set addedMethods = new TreeSet(); - Set addedFields = new TreeSet(); - Set changedMethods = new TreeSet(); - Set changedFields = new TreeSet(); + final Set removedMethods = new TreeSet(); + final Set removedFields = new TreeSet(); + final Set addedMethods = new TreeSet(); + final Set addedFields = new TreeSet(); + final Set changedMethods = new TreeSet(); + final Set changedFields = new TreeSet(); handler.startChanged(); - for (String s : both) { - ClassInfo oci = oldClassInfo.get(s); - ClassInfo nci = newClassInfo.get(s); + for (final String s : both) { + final ClassInfo oci = oldClassInfo.get(s); + final ClassInfo nci = newClassInfo.get(s); if (criteria.validClass(oci) || criteria.validClass(nci)) { - Map oldMethods = oci.getMethodMap(); - Map oldFields = oci.getFieldMap(); - Map newMethods = nci.getMethodMap(); - Map newFields = nci.getFieldMap(); + final Map oldMethods = oci.getMethodMap(); + final Map oldFields = oci.getFieldMap(); + final Map newMethods = nci.getMethodMap(); + final Map newFields = nci.getFieldMap(); - Map extNewMethods = new HashMap(newMethods); - Map extNewFields = new HashMap(newFields); + final Map extNewMethods = new HashMap(newMethods); + final Map extNewFields = new HashMap(newFields); String superClass = nci.getSupername(); while (superClass != null && newClassInfo.containsKey(superClass)) { - ClassInfo sci = newClassInfo.get(superClass); - for (Map.Entry entry : sci.getFieldMap().entrySet()) { + final ClassInfo sci = newClassInfo.get(superClass); + for (final Map.Entry entry : sci.getFieldMap().entrySet()) { if (!(entry.getValue()).isPrivate() && !extNewFields.containsKey(entry.getKey())) { extNewFields.put(entry.getKey(), entry.getValue()); } } - for (Map.Entry entry : sci.getMethodMap().entrySet()) { + for (final Map.Entry entry : sci.getMethodMap().entrySet()) { if (!(entry.getValue()).isPrivate() && !extNewMethods.containsKey(entry.getKey())) { extNewMethods.put(entry.getKey(), entry.getValue()); @@ -374,20 +374,20 @@ public class JarDiff superClass = sci.getSupername(); } - for (Map.Entry entry : oldMethods.entrySet()) { + for (final Map.Entry entry : oldMethods.entrySet()) { if (criteria.validMethod(entry.getValue())) removedMethods.add(entry.getKey()); } - for (Map.Entry entry : oldFields.entrySet()) { + for (final Map.Entry entry : oldFields.entrySet()) { if (criteria.validField(entry.getValue())) removedFields.add(entry.getKey()); } - for (Map.Entry entry : newMethods.entrySet()) { + for (final Map.Entry entry : newMethods.entrySet()) { if (criteria.validMethod(entry.getValue())) addedMethods.add(entry.getKey()); } - for (Map.Entry entry : newFields.entrySet()) { + for (final Map.Entry entry : newFields.entrySet()) { if (criteria.validField(entry.getValue())) addedFields.add(entry.getKey()); } @@ -409,22 +409,22 @@ public class JarDiff Iterator j = changedMethods.iterator(); while (j.hasNext()) { - String desc = j.next(); - MethodInfo oldInfo = oldMethods.get(desc); - MethodInfo newInfo = newMethods.get(desc); + final String desc = j.next(); + final MethodInfo oldInfo = oldMethods.get(desc); + final MethodInfo newInfo = newMethods.get(desc); if (!criteria.differs(oldInfo, newInfo)) j.remove(); } j = changedFields.iterator(); while (j.hasNext()) { - String desc = j.next(); - FieldInfo oldInfo = oldFields.get(desc); - FieldInfo newInfo = newFields.get(desc); + final String desc = j.next(); + final FieldInfo oldInfo = oldFields.get(desc); + final FieldInfo newInfo = newFields.get(desc); if (!criteria.differs(oldInfo, newInfo)) j.remove(); } - boolean classchanged = criteria.differs(oci, nci); + final boolean classchanged = criteria.differs(oci, nci); if (classchanged || !removedMethods.isEmpty() || !removedFields.isEmpty() || !addedMethods.isEmpty() || !addedFields.isEmpty() || !changedMethods.isEmpty() @@ -432,19 +432,19 @@ public class JarDiff handler.startClassChanged(s); handler.startRemoved(); - for (String field : removedFields) { + for (final String field : removedFields) { handler.fieldRemoved(oldFields.get(field)); } - for (String method : removedMethods) { + for (final String method : removedMethods) { handler.methodRemoved(oldMethods.get(method)); } handler.endRemoved(); handler.startAdded(); - for (String field : addedFields) { + for (final String field : addedFields) { handler.fieldAdded(newFields.get(field)); } - for (String method : addedMethods) { + for (final String method : addedMethods) { handler.methodAdded(newMethods.get(method)); } handler.endAdded(); @@ -453,36 +453,43 @@ public class JarDiff if (classchanged) { // Was only deprecated? if (wasDeprecated(oci, nci) - && !criteria.differs(cloneDeprecated(oci), nci)) + && !criteria.differs(cloneDeprecated(oci), nci)) { handler.classDeprecated(oci, nci); - else + } else { handler.classChanged(oci, nci); + } } - for (String field : changedFields) { - FieldInfo oldFieldInfo = oldFields.get(field); - FieldInfo newFieldInfo = newFields.get(field); + for (final String field : changedFields) { + final FieldInfo oldFieldInfo = oldFields.get(field); + final FieldInfo newFieldInfo = newFields.get(field); // Was only deprecated? if (wasDeprecated(oldFieldInfo, newFieldInfo) && !criteria.differs( cloneDeprecated(oldFieldInfo), - newFieldInfo)) + newFieldInfo)) { handler.fieldDeprecated(oldFieldInfo, newFieldInfo); - else + } else if( !criteria.differsBinary(oldFieldInfo, newFieldInfo)) { + handler.fieldChangedCompat(oldFieldInfo, newFieldInfo); + } else { handler.fieldChanged(oldFieldInfo, newFieldInfo); + } } - for (String method : changedMethods) { - MethodInfo oldMethodInfo = oldMethods.get(method); - MethodInfo newMethodInfo = newMethods.get(method); + for (final String method : changedMethods) { + final MethodInfo oldMethodInfo = oldMethods.get(method); + final MethodInfo newMethodInfo = newMethods.get(method); // Was only deprecated? if (wasDeprecated(oldMethodInfo, newMethodInfo) && !criteria.differs( cloneDeprecated(oldMethodInfo), - newMethodInfo)) + newMethodInfo)) { handler.methodDeprecated(oldMethodInfo, newMethodInfo); - else + } else if ( !criteria.differsBinary(oldMethodInfo, newMethodInfo) ) { + handler.methodChangedCompat(oldMethodInfo, newMethodInfo); + } else { handler.methodChanged(oldMethodInfo, newMethodInfo); + } } handler.endChanged(); handler.endClassChanged(); @@ -505,19 +512,28 @@ public class JarDiff * Determines if an {@link AbstractInfo} was deprecated. (Shortcut to avoid * creating cloned deprecated infos). */ - private static boolean wasDeprecated(AbstractInfo oldInfo, - AbstractInfo newInfo) { + private static boolean wasDeprecated(final AbstractInfo oldInfo, + final AbstractInfo newInfo) { return !oldInfo.isDeprecated() && newInfo.isDeprecated(); } + /** + * Determines if an {@link AbstractInfo} was deprecated. (Shortcut to avoid + * creating cloned deprecated infos). + */ + private static boolean throwClauseDiffers(final AbstractInfo oldInfo, + final AbstractInfo newInfo) { + return !oldInfo.isDeprecated() && newInfo.isDeprecated(); + } + /** * Clones the class info, but changes access, setting deprecated flag. - * + * * @param classInfo * the original class info * @return the cloned and deprecated info. */ - private static ClassInfo cloneDeprecated(ClassInfo classInfo) { + private static ClassInfo cloneDeprecated(final ClassInfo classInfo) { return new ClassInfo(classInfo.getVersion(), classInfo.getAccess() | Opcodes.ACC_DEPRECATED, classInfo.getName(), classInfo.getSignature(), classInfo.getSupername(), @@ -527,12 +543,12 @@ public class JarDiff /** * Clones the method, but changes access, setting deprecated flag. - * + * * @param methodInfo * the original method info * @return the cloned and deprecated method info. */ - private static MethodInfo cloneDeprecated(MethodInfo methodInfo) { + private static MethodInfo cloneDeprecated(final MethodInfo methodInfo) { return new MethodInfo(methodInfo.getAccess() | Opcodes.ACC_DEPRECATED, methodInfo.getName(), methodInfo.getDesc(), methodInfo.getSignature(), methodInfo.getExceptions()); @@ -540,12 +556,12 @@ public class JarDiff /** * Clones the field info, but changes access, setting deprecated flag. - * + * * @param fieldInfo * the original field info * @return the cloned and deprecated field info. */ - private static FieldInfo cloneDeprecated(FieldInfo fieldInfo) { + private static FieldInfo cloneDeprecated(final FieldInfo fieldInfo) { return new FieldInfo(fieldInfo.getAccess() | Opcodes.ACC_DEPRECATED, fieldInfo.getName(), fieldInfo.getDesc(), fieldInfo.getSignature(), fieldInfo.getValue()); diff --git a/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java b/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java index 90fb382..6cf25d6 100644 --- a/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java +++ b/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java @@ -28,6 +28,18 @@ import java.util.Set; */ public class PublicDiffCriteria implements DiffCriteria { + @Override + public boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof PublicDiffCriteria) ) { + return false; + } + return true; // no states + } + @Override + public String toString() { return "PublicDiffCriteria"; } + /** * Check if a class is valid. * If the class is not synthetic and public, return true. @@ -35,7 +47,7 @@ public class PublicDiffCriteria implements DiffCriteria * @param info Info describing the class. * @return True if the class meets the criteria, false otherwise. */ - public boolean validClass(ClassInfo info) { + public boolean validClass(final ClassInfo info) { return !info.isSynthetic() && info.isPublic(); } @@ -46,7 +58,7 @@ public class PublicDiffCriteria implements DiffCriteria * @param info Info describing the method. * @return True if the method meets the criteria, false otherwise. */ - public boolean validMethod(MethodInfo info) { + public boolean validMethod(final MethodInfo info) { return !info.isSynthetic() && info.isPublic(); } @@ -57,7 +69,7 @@ public class PublicDiffCriteria implements DiffCriteria * @param info Info describing the field. * @return True if the field meets the criteria, false otherwise. */ - public boolean validField(FieldInfo info) { + public boolean validField(final FieldInfo info) { return !info.isSynthetic() && info.isPublic(); } @@ -70,7 +82,7 @@ public class PublicDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the class. * @return True if the classes differ, false otherwise. */ - public boolean differs(ClassInfo oldInfo, ClassInfo newInfo) { + public boolean differs(final ClassInfo oldInfo, final ClassInfo newInfo) { if (Tools.isClassAccessChange(oldInfo.getAccess(), newInfo.getAccess())) return true; // Yes classes can have a null supername, e.g. java.lang.Object ! @@ -99,20 +111,18 @@ public class PublicDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the method. * @return True if the methods differ, false otherwise. */ - public boolean differs(MethodInfo oldInfo, MethodInfo newInfo) { - if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) + public boolean differs(final MethodInfo oldInfo, final MethodInfo newInfo) { + if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { + return true; + } + if (Tools.isThrowsClauseChange(oldInfo.getExceptions(), newInfo.getExceptions())) { + return true; + } + return false; + } + public boolean differsBinary(final MethodInfo oldInfo, final MethodInfo newInfo) { + if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { return true; - if (oldInfo.getExceptions() == null - || newInfo.getExceptions() == null) { - if (oldInfo.getExceptions() != newInfo.getExceptions()) - return true; - } else { - final Set oldExceptions - = new HashSet(Arrays.asList(oldInfo.getExceptions())); - final Set newExceptions - = new HashSet(Arrays.asList(newInfo.getExceptions())); - if (!oldExceptions.equals(newExceptions)) - return true; } return false; } @@ -126,14 +136,19 @@ public class PublicDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the field. * @return True if the fields differ, false otherwise. */ - public boolean differs(FieldInfo oldInfo, FieldInfo newInfo) { - if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) + public boolean differs(final FieldInfo oldInfo, final FieldInfo newInfo) { + if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { return true; - if (oldInfo.getValue() == null || newInfo.getValue() == null) { - if (oldInfo.getValue() != newInfo.getValue()) - return true; - } else if (!oldInfo.getValue().equals(newInfo.getValue())) + } + if (Tools.isFieldValueChange(oldInfo.getValue(), newInfo.getValue())) { return true; + } + return false; + } + public boolean differsBinary(final FieldInfo oldInfo, final FieldInfo newInfo) { + if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { + return true; + } return false; } } diff --git a/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java index ceaf0d2..578f637 100644 --- a/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java +++ b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java @@ -28,6 +28,18 @@ import java.util.Set; */ public class SimpleDiffCriteria implements DiffCriteria { + @Override + public boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof SimpleDiffCriteria) ) { + return false; + } + return true; // no states + } + @Override + public String toString() { return "SimpleDiffCriteria"; } + /** * Check if a class is valid. * If the class is not synthetic and is public or protected, return true. @@ -35,7 +47,7 @@ public class SimpleDiffCriteria implements DiffCriteria * @param info Info describing the class. * @return True if the class meets the criteria, false otherwise. */ - public boolean validClass(ClassInfo info) { + public boolean validClass(final ClassInfo info) { return !info.isSynthetic() && (info.isPublic() || info.isProtected()); } @@ -46,7 +58,7 @@ public class SimpleDiffCriteria implements DiffCriteria * @param info Info describing the method. * @return True if the method meets the criteria, false otherwise. */ - public boolean validMethod(MethodInfo info) { + public boolean validMethod(final MethodInfo info) { return !info.isSynthetic() && (info.isPublic() || info.isProtected()); } @@ -57,7 +69,7 @@ public class SimpleDiffCriteria implements DiffCriteria * @param info Info describing the field. * @return True if the field meets the criteria, false otherwise. */ - public boolean validField(FieldInfo info) { + public boolean validField(final FieldInfo info) { return !info.isSynthetic() && (info.isPublic() || info.isProtected()); } @@ -70,7 +82,7 @@ public class SimpleDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the class. * @return True if the classes differ, false otherwise. */ - public boolean differs(ClassInfo oldInfo, ClassInfo newInfo) { + public boolean differs(final ClassInfo oldInfo, final ClassInfo newInfo) { if (Tools.isClassAccessChange(oldInfo.getAccess(), newInfo.getAccess())) return true; // Yes classes can have a null supername, e.g. java.lang.Object ! @@ -99,20 +111,18 @@ public class SimpleDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the method. * @return True if the methods differ, false otherwise. */ - public boolean differs(MethodInfo oldInfo, MethodInfo newInfo) { - if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) + public boolean differs(final MethodInfo oldInfo, final MethodInfo newInfo) { + if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { + return true; + } + if (Tools.isThrowsClauseChange(oldInfo.getExceptions(), newInfo.getExceptions())) { + return true; + } + return false; + } + public boolean differsBinary(final MethodInfo oldInfo, final MethodInfo newInfo) { + if (Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { return true; - if (oldInfo.getExceptions() == null - || newInfo.getExceptions() == null) { - if (oldInfo.getExceptions() != newInfo.getExceptions()) - return true; - } else { - final Set oldExceptions - = new HashSet(Arrays.asList(oldInfo.getExceptions())); - final Set newExceptions - = new HashSet(Arrays.asList(newInfo.getExceptions())); - if (!oldExceptions.equals(newExceptions)) - return true; } return false; } @@ -126,14 +136,19 @@ public class SimpleDiffCriteria implements DiffCriteria * @param newInfo Info about the new version of the field. * @return True if the fields differ, false otherwise. */ - public boolean differs(FieldInfo oldInfo, FieldInfo newInfo) { - if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) + public boolean differs(final FieldInfo oldInfo, final FieldInfo newInfo) { + if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { return true; - if (oldInfo.getValue() == null || newInfo.getValue() == null) { - if (oldInfo.getValue() != newInfo.getValue()) - return true; - } else if (!oldInfo.getValue().equals(newInfo.getValue())) + } + if (Tools.isFieldValueChange(oldInfo.getValue(), newInfo.getValue())) { return true; + } + return false; + } + public boolean differsBinary(final FieldInfo oldInfo, final FieldInfo newInfo) { + if (Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess())) { + return true; + } return false; } } diff --git a/api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java b/api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java index f5f7176..8f0d95a 100644 --- a/api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java +++ b/api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java @@ -16,7 +16,6 @@ */ package org.osjava.jardiff; -import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; @@ -25,7 +24,7 @@ import java.io.OutputStreamWriter; import org.objectweb.asm.Type; /** - * A specific type of DiffHandler which uses an OutputStream to create an + * A specific type of DiffHandler which uses an OutputStream to create an * XML document describing the changes in the diff. * This is needed for java 1.2 compatibility for the ant task. * @@ -55,28 +54,28 @@ public class StreamDiffHandler implements DiffHandler out = new BufferedWriter( new OutputStreamWriter(System.out, "UTF-8") ); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Create a new StreamDiffHandler with the specified OutputStream. * * @param out Where to write output. */ - public StreamDiffHandler(OutputStream out) + public StreamDiffHandler(final OutputStream out) throws DiffException { try { this.out = new BufferedWriter( new OutputStreamWriter(out, "UTF-8") ); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Start the diff. * This writes out the start of a <diff> node. @@ -86,7 +85,7 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void startDiff(String oldJar, String newJar) throws DiffException { + public void startDiff(final String oldJar, final String newJar) throws DiffException { try { out.write(""); out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -110,7 +109,7 @@ public class StreamDiffHandler implements DiffHandler public void startOldContents() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -124,7 +123,7 @@ public class StreamDiffHandler implements DiffHandler public void startNewContents() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -136,12 +135,12 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void contains(ClassInfo info) throws DiffException { + public void contains(final ClassInfo info) throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -155,7 +154,7 @@ public class StreamDiffHandler implements DiffHandler public void endOldContents() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } @@ -169,11 +168,11 @@ public class StreamDiffHandler implements DiffHandler public void endNewContents() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Start the removed node. * This writes out a <removed> node. @@ -184,11 +183,11 @@ public class StreamDiffHandler implements DiffHandler public void startRemoved() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out class info for a removed class. * This writes out the nodes describing a class @@ -197,14 +196,14 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classRemoved(ClassInfo info) throws DiffException { + public void classRemoved(final ClassInfo info) throws DiffException { try { writeClassInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * End the removed section. * This closes the <removed> tag. @@ -215,11 +214,11 @@ public class StreamDiffHandler implements DiffHandler public void endRemoved() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Start the added section. * This opens the <added> tag. @@ -230,11 +229,11 @@ public class StreamDiffHandler implements DiffHandler public void startAdded() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out the class info for an added class. * This writes out the nodes describing an added class. @@ -243,14 +242,14 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classAdded(ClassInfo info) throws DiffException { + public void classAdded(final ClassInfo info) throws DiffException { try { writeClassInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * End the added section. * This closes the <added> tag. @@ -261,11 +260,11 @@ public class StreamDiffHandler implements DiffHandler public void endAdded() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Start the changed section. * This writes out the <changed> node. @@ -276,11 +275,11 @@ public class StreamDiffHandler implements DiffHandler public void startChanged() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Start a changed section for an individual class. * This writes out an <classchanged> node with the real class @@ -290,17 +289,17 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void startClassChanged(String internalName) throws DiffException + public void startClassChanged(final String internalName) throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out info about a removed field. * This just writes out the field info, it will be inside a start/end @@ -310,48 +309,48 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldRemoved(FieldInfo info) throws DiffException { + public void fieldRemoved(final FieldInfo info) throws DiffException { try { writeFieldInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out info about a removed method. - * This just writes out the method info, it will be inside a start/end + * This just writes out the method info, it will be inside a start/end * removed section. * * @param info Info about the method that's been removed. * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodRemoved(MethodInfo info) throws DiffException { + public void methodRemoved(final MethodInfo info) throws DiffException { try { writeMethodInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out info about an added field. - * This just writes out the field info, it will be inside a start/end + * This just writes out the field info, it will be inside a start/end * added section. * * @param info Info about the added field. * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldAdded(FieldInfo info) throws DiffException { + public void fieldAdded(final FieldInfo info) throws DiffException { try { writeFieldInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out info about a added method. * This just writes out the method info, it will be inside a start/end @@ -361,17 +360,17 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodAdded(MethodInfo info) throws DiffException { + public void methodAdded(final MethodInfo info) throws DiffException { try { writeMethodInfo(info); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out info aboout a changed class. - * This writes out a <classchange> node, followed by a + * This writes out a <classchange> node, followed by a * <from> node, with the old information about the class * followed by a <to> node with the new information about the * class. @@ -381,8 +380,8 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void classChanged(ClassInfo oldInfo, ClassInfo newInfo) - throws DiffException + public void classChanged(final ClassInfo oldInfo, final ClassInfo newInfo) + throws DiffException { try { out.write(""); @@ -390,22 +389,22 @@ public class StreamDiffHandler implements DiffHandler out.write(""); writeClassInfo(newInfo); out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Invokes {@link #classChanged(ClassInfo, ClassInfo)}. */ - public void classDeprecated(ClassInfo oldInfo, ClassInfo newInfo) + public void classDeprecated(final ClassInfo oldInfo, final ClassInfo newInfo) throws DiffException { classChanged(oldInfo, newInfo); } /** - * Write out info aboout a changed field. - * This writes out a <fieldchange> node, followed by a + * Write out info about a changed field. + * This writes out a <fieldchange> node, followed by a * <from> node, with the old information about the field * followed by a <to> node with the new information about the * field. @@ -415,8 +414,8 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void fieldChanged(FieldInfo oldInfo, FieldInfo newInfo) - throws DiffException + public void fieldChanged(final FieldInfo oldInfo, final FieldInfo newInfo) + throws DiffException { try { out.write(""); @@ -424,22 +423,48 @@ public class StreamDiffHandler implements DiffHandler out.write(""); writeFieldInfo(newInfo); out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + + /** + * Write out info about a binary compatible changed field. + * This writes out a <fieldchangecompat> node, followed by a + * <from> node, with the old information about the field + * followed by a <to> node with the new information about the + * field. + * + * @param oldInfo Info about the old field. + * @param newInfo Info about the new field. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void fieldChangedCompat(final FieldInfo oldInfo, final FieldInfo newInfo) + throws DiffException + { + try { + out.write(""); + writeFieldInfo(oldInfo); + out.write(""); + writeFieldInfo(newInfo); + out.write(""); + } catch (final IOException ioe) { + throw new DiffException(ioe); + } + } + /** * Invokes {@link #fieldChanged(FieldInfo, FieldInfo)}. */ - public void fieldDeprecated(FieldInfo oldInfo, FieldInfo newInfo) + public void fieldDeprecated(final FieldInfo oldInfo, final FieldInfo newInfo) throws DiffException { fieldChanged(oldInfo, newInfo); } /** - * Write out info aboout a changed method. - * This writes out a <methodchange> node, followed by a + * Write out info about a changed method. + * This writes out a <methodchange> node, followed by a * <from> node, with the old information about the method * followed by a <to> node with the new information about the * method. @@ -449,7 +474,7 @@ public class StreamDiffHandler implements DiffHandler * @throws DiffException when there is an underlying exception, e.g. * writing to a file caused an IOException */ - public void methodChanged(MethodInfo oldInfo, MethodInfo newInfo) + public void methodChanged(final MethodInfo oldInfo, final MethodInfo newInfo) throws DiffException { try { @@ -458,15 +483,41 @@ public class StreamDiffHandler implements DiffHandler out.write(""); writeMethodInfo(newInfo); out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + + /** + * Write out info about a binary compatible changed method. + * This writes out a <methodchangecompat> node, followed by a + * <from> node, with the old information about the method + * followed by a <to> node with the new information about the + * method. + * + * @param oldInfo Info about the old method. + * @param newInfo Info about the new method. + * @throws DiffException when there is an underlying exception, e.g. + * writing to a file caused an IOException + */ + public void methodChangedCompat(final MethodInfo oldInfo, final MethodInfo newInfo) + throws DiffException + { + try { + out.write(""); + writeMethodInfo(oldInfo); + out.write(""); + writeMethodInfo(newInfo); + out.write(""); + } catch (final IOException ioe) { + throw new DiffException(ioe); + } + } + /** * Invokes {@link #methodChanged(MethodInfo, MethodInfo)}. */ - public void methodDeprecated(MethodInfo oldInfo, MethodInfo newInfo) + public void methodDeprecated(final MethodInfo oldInfo, final MethodInfo newInfo) throws DiffException { methodChanged(oldInfo, newInfo); } @@ -481,11 +532,11 @@ public class StreamDiffHandler implements DiffHandler public void endClassChanged() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * End the changed section. * This closes the <changed> node. @@ -496,11 +547,11 @@ public class StreamDiffHandler implements DiffHandler public void endChanged() throws DiffException { try { out.write(""); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * End the diff. * This closes the <diff> node. @@ -513,11 +564,11 @@ public class StreamDiffHandler implements DiffHandler out.write(""); out.newLine(); out.close(); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new DiffException(ioe); } } - + /** * Write out information about a class. * This writes out a <class> node, which contains information about @@ -526,7 +577,7 @@ public class StreamDiffHandler implements DiffHandler * @param info Info about the class to write out. * @throws IOException when there is an underlying IOException. */ - protected void writeClassInfo(ClassInfo info) throws IOException { + protected void writeClassInfo(final ClassInfo info) throws IOException { out.write(""); } - String[] interfaces = info.getInterfaces(); + final String[] interfaces = info.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { out.write(""); } - + /** * Write out information about a method. * This writes out a <method> node which contains information about - * the arguments, the return type, and the exceptions thrown by the + * the arguments, the return type, and the exceptions thrown by the * method. * * @param info Info about the method. * @throws IOException when there is an underlying IOException. */ - protected void writeMethodInfo(MethodInfo info) throws IOException { + protected void writeMethodInfo(final MethodInfo info) throws IOException { out.write(""); } - + /** * Write out information about a field. * This writes out a <field> node with attributes describing the @@ -600,7 +651,7 @@ public class StreamDiffHandler implements DiffHandler * @param info Info about the field. * @throws IOException when there is an underlying IOException. */ - protected void writeFieldInfo(FieldInfo info) throws IOException { + protected void writeFieldInfo(final FieldInfo info) throws IOException { out.write(""); } - + /** * Add attributes describing some access flags. * This adds the attributes to the attr field. @@ -634,7 +685,7 @@ public class StreamDiffHandler implements DiffHandler * @param info Info describing the access flags. * @throws IOException when there is an underlying IOException. */ - protected void addAccessFlags(AbstractInfo info) throws IOException { + protected void addAccessFlags(final AbstractInfo info) throws IOException { out.write(" access=\""); // Doesn't need escaping. out.write(info.getAccessType()); @@ -672,19 +723,19 @@ public class StreamDiffHandler implements DiffHandler if (info.isVolatile()) out.write(" volatile=\"yes\""); } - + /** * Add the method nodes for the method descriptor. - * This writes out an <arguments> node containing the + * This writes out an <arguments> node containing the * argument types for the method, followed by a <return> node * containing the return type. * * @param desc The descriptor for the method to write out. * @throws IOException when there is an underlying IOException. */ - protected void addMethodNodes(String desc) throws IOException { - Type[] args = Type.getArgumentTypes(desc); - Type ret = Type.getReturnType(desc); + protected void addMethodNodes(final String desc) throws IOException { + final Type[] args = Type.getArgumentTypes(desc); + final Type ret = Type.getReturnType(desc); out.write(""); for (int i = 0; i < args.length; i++) addTypeNode(args[i]); @@ -693,17 +744,17 @@ public class StreamDiffHandler implements DiffHandler addTypeNode(ret); out.write(""); } - + /** * Add a type node for the specified descriptor. * * @param desc A type descriptor. * @throws IOException when there is an underlying IOException. */ - protected void addTypeNode(String desc) throws IOException { + protected void addTypeNode(final String desc) throws IOException { addTypeNode(Type.getType(desc)); } - + /** * Add a type node for the specified type. * This writes out a <type> node with attributes describing @@ -765,9 +816,9 @@ public class StreamDiffHandler implements DiffHandler * @return the formatted text */ private final String xmlEscape(final String str) { - StringBuffer ret = new StringBuffer(str.length()); + final StringBuffer ret = new StringBuffer(str.length()); for(int i=0;i + * Note that + * following Java Language Specification, Java SE 7 Edition: + *
    + *
  • 13.4.21 Method and Constructor Throws
      + *
    • Changes to the throws clause of methods or constructors + * do not break compatibility with pre-existing binaries; + * these clauses are checked only at compile time. + *
    • + *
  • + *
+ *

+ * @param oldThrows + * @param newThrows + * + * @return + */ + public static boolean isThrowsClauseChange(final String[] oldThrows, final String[] newThrows) { + if (oldThrows == null || newThrows == null) { + return oldThrows != newThrows; + } else { + final Set oldExceptions = new HashSet(Arrays.asList(oldThrows)); + final Set newExceptions = new HashSet(Arrays.asList(newThrows)); + return !oldExceptions.equals(newExceptions); + } + } + + /** + * Returns whether a field's oldValue differs with newValue. + *

+ * Note that + * following Java Language Specification, Java SE 7 Edition: + *

    + *
  • 13.4.9 final Fields and Constants
      + *
    • Deleting the keyword final or changing the value to which a field is initialized + * does not break compatibility with existing binaries. + *
    • + *
  • + *
+ *

+ * @param oldValue + * @param newValue + * @return + */ + public static boolean isFieldValueChange(final Object oldValue, final Object newValue) { + if (oldValue == null || newValue == null) { + return oldValue != newValue; + } else { + return !oldValue.equals(newValue); + } + } } diff --git a/api/src/main/java/org/semver/Delta.java b/api/src/main/java/org/semver/Delta.java index d38777d..e148a72 100755 --- a/api/src/main/java/org/semver/Delta.java +++ b/api/src/main/java/org/semver/Delta.java @@ -106,6 +106,23 @@ public final class Delta { } + @Immutable + public static class CompatChange extends Difference { + + private final AbstractInfo modifiedInfo; + + public CompatChange(@Nonnull final String className, @Nonnull final AbstractInfo info, @Nonnull final AbstractInfo modifiedInfo) { + super(className, info); + + this.modifiedInfo = modifiedInfo; + } + + public AbstractInfo getModifiedInfo() { + return this.modifiedInfo; + } + + } + @Immutable public static class Deprecate extends Difference { @@ -155,7 +172,8 @@ public final class Delta { contains(this.differences, Remove.class)) { return CompatibilityType.NON_BACKWARD_COMPATIBLE; } else if (contains(this.differences, Add.class) || - contains(this.differences, Deprecate.class)) { + contains(this.differences, CompatChange.class) || + contains(this.differences, Deprecate.class)) { return CompatibilityType.BACKWARD_COMPATIBLE_USER; } else { return CompatibilityType.BACKWARD_COMPATIBLE_IMPLEMENTER; diff --git a/api/src/main/java/org/semver/Dumper.java b/api/src/main/java/org/semver/Dumper.java index 68018fc..651d2df 100755 --- a/api/src/main/java/org/semver/Dumper.java +++ b/api/src/main/java/org/semver/Dumper.java @@ -18,8 +18,10 @@ package org.semver; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -28,8 +30,10 @@ import java.util.Set; import org.osjava.jardiff.AbstractInfo; import org.osjava.jardiff.ClassInfo; +import org.osjava.jardiff.FieldInfo; +import org.osjava.jardiff.MethodInfo; +import org.osjava.jardiff.Tools; import org.semver.Delta.Difference; -import org.semver.Delta.Change; /** * @@ -52,11 +56,14 @@ public class Dumper { } protected static String extractDetails(final Difference difference) { - if (difference instanceof Change) { - final Change change = (Change) difference; - return extractDetails(difference.getInfo())+", access "+extractAccessDetails(difference.getInfo(), change.getModifiedInfo()); + if (difference instanceof Delta.Change) { + final Delta.Change change = (Delta.Change) difference; + return extractDetails(difference.getInfo())+", "+extractChangeDetails(difference.getInfo(), change.getModifiedInfo()); + } else if (difference instanceof Delta.CompatChange) { + final Delta.CompatChange change = (Delta.CompatChange) difference; + return extractDetails(difference.getInfo())+", "+extractCompatChangeDetails(difference.getInfo(), change.getModifiedInfo()); } else { - return extractDetails(difference.getInfo())+", access "+extractAccessDetails(difference.getInfo()); + return extractDetails(difference.getInfo())+", access["+extractAccessDetails(difference.getInfo())+"]"; } } @@ -74,6 +81,51 @@ public class Dumper { return builder.toString(); } + protected static String extractChangeDetails(final AbstractInfo previousInfo, final AbstractInfo currentInfo) { + final StringBuilder builder = new StringBuilder(); + builder.append(", access["); + return extractAccessDetails(builder, previousInfo, currentInfo).append("]").toString().trim(); + } + + protected static String extractCompatChangeDetails(final AbstractInfo previousInfo, final AbstractInfo currentInfo) { + final StringBuilder builder = new StringBuilder(); + if( previousInfo instanceof MethodInfo ) { + final MethodInfo mPreInfo = (MethodInfo)previousInfo; + final MethodInfo mCurInfo = (MethodInfo)currentInfo; + final String[] preThrows = mPreInfo.getExceptions(); + final String[] curThrows = mCurInfo.getExceptions(); + if (Tools.isThrowsClauseChange(preThrows, curThrows)) { + final HashSet preThrowsSet; + final HashSet curThrowsSet; + if( null != preThrows ) { + preThrowsSet = new HashSet(Arrays.asList(preThrows)); + } else { + preThrowsSet = new HashSet(); + } + if( null != curThrows ) { + curThrowsSet = new HashSet(Arrays.asList(curThrows)); + } else { + curThrowsSet = new HashSet(); + } + preThrowsSet.removeAll(curThrowsSet); + curThrowsSet.removeAll(preThrowsSet); + builder.append("throws[removed").append(preThrowsSet.toString()) + .append(", added").append(curThrowsSet.toString()).append("]"); + } + } else if( previousInfo instanceof FieldInfo ) { + final FieldInfo fPreInfo = (FieldInfo)previousInfo; + final FieldInfo fCurInfo = (FieldInfo)currentInfo; + final Object preValue = fPreInfo.getValue(); + final Object curValue = fCurInfo.getValue(); + if (Tools.isFieldValueChange(preValue, curValue)) { + builder.append("value[old: ").append(preValue) + .append(" != new: ").append(curValue).append("]"); + } + } + builder.append(", access["); + return extractAccessDetails(builder, previousInfo, currentInfo).append("]").toString().trim(); + } + protected static void accumulateAccessDetails(final String access, final boolean previousAccess, final boolean currentAccess, final List added, final List removed) { if (previousAccess != currentAccess) { if (previousAccess) { @@ -85,6 +137,9 @@ public class Dumper { } protected static String extractAccessDetails(final AbstractInfo previousInfo, final AbstractInfo currentInfo) { + return extractAccessDetails(new StringBuilder(), previousInfo, currentInfo).toString().trim(); + } + protected static StringBuilder extractAccessDetails(final StringBuilder details, final AbstractInfo previousInfo, final AbstractInfo currentInfo) { final List added = new LinkedList(); final List removed = new LinkedList(); accumulateAccessDetails("abstract", previousInfo.isAbstract(), currentInfo.isAbstract(), added, removed); @@ -106,7 +161,6 @@ public class Dumper { accumulateAccessDetails("transcient", previousInfo.isTransient(), currentInfo.isTransient(), added, removed); accumulateAccessDetails("varargs", previousInfo.isVarargs(), currentInfo.isVarargs(), added, removed); accumulateAccessDetails("volatile", previousInfo.isVolatile(), currentInfo.isVolatile(), added, removed); - final StringBuilder details = new StringBuilder(); if (!added.isEmpty()) { details.append("added: "); for (final String access : added) { @@ -119,7 +173,7 @@ public class Dumper { details.append(access).append(" "); } } - return details.toString().trim(); + return details; } protected static void accumulateAccessDetails(final String access, final boolean hasAccess, final List accessList) { @@ -159,9 +213,7 @@ public class Dumper { } /** - * * Dumps on {@link System#out} all differences, sorted by class name. - * * @param delta the delta to be dumped */ public static void dump(final Delta delta) { @@ -170,7 +222,6 @@ public class Dumper { /** * Dumps on out all differences, sorted by class name. - * * @param delta the delta to be dumped * @param out */ @@ -182,7 +233,6 @@ public class Dumper { /** * Dumps on out all of the given sorted differences. - * * @param sortedDifferences the sorted differences to be dumped * @param out the print output stream */ @@ -192,7 +242,8 @@ public class Dumper { if (!currentClassName.equals(difference.getClassName())) { out.println("Class "+difference.getClassName()); } - out.println(" "+extractActionType(difference)+" "+extractInfoType(difference.getInfo())+" "+extractDetails(difference)); + out.println(" "+extractActionType(difference)+" "+extractInfoType(difference.getInfo())+ + " "+extractDetails(difference)); currentClassName = difference.getClassName(); } } @@ -212,6 +263,7 @@ public class Dumper { final List diffsAdd = new ArrayList(); final List diffsChange = new ArrayList(); + final List diffsCompatChange = new ArrayList(); final List diffsDeprecate = new ArrayList(); final List diffsRemove = new ArrayList(); final Map className2DiffCount = new HashMap(); @@ -235,6 +287,9 @@ public class Dumper { } else if( diff instanceof Delta.Change ) { diffsChange.add(diff); dc.changes++; + } else if( diff instanceof Delta.CompatChange ) { + diffsCompatChange.add(diff); + dc.compatChanges++; } else if( diff instanceof Delta.Deprecate ) { diffsDeprecate.add(diff); dc.deprecates++; @@ -245,6 +300,7 @@ public class Dumper { } Collections.sort(diffsAdd); Collections.sort(diffsChange); + Collections.sort(diffsCompatChange); Collections.sort(diffsDeprecate); Collections.sort(diffsRemove); @@ -254,6 +310,7 @@ public class Dumper { System.err.println("Summary: "+diffs.size()+" differences in "+classNames.size()+" classes:"); System.err.println(" Remove "+diffsRemove.size()+ ", Change "+diffsChange.size()+ + ", CompatChange "+diffsCompatChange.size()+ ", Deprecate "+diffsDeprecate.size()+ ", Add "+diffsAdd.size()); System.err.printf("%n"); @@ -271,6 +328,9 @@ public class Dumper { System.err.printf("%n%nChanges%n%n"); dump(diffsChange, System.err); + System.err.printf("%n%nCompatChanges%n%n"); + dump(diffsCompatChange, System.err); + System.err.printf("%n%nDeprecates%n%n"); dump(diffsDeprecate, System.err); @@ -280,16 +340,17 @@ public class Dumper { } static class DiffCount { - public DiffCount(String name) { this.name = name; } + public DiffCount(final String name) { this.name = name; } public final String name; public int removes; public int changes; + public int compatChanges; public int deprecates; public int additions; - public String toString() { return name+": Remove "+removes+", Change "+changes+", Deprecate "+deprecates+", Add "+additions; } + public String toString() { return name+": Remove "+removes+", Change "+changes+", CompatChange "+compatChanges+", Deprecate "+deprecates+", Add "+additions; } public String format(final int iwidth) { - return String.format("Remove %"+iwidth+"d, Change %"+iwidth+"d, Deprecate %"+iwidth+"d, Add %"+iwidth+"d", - removes, changes, deprecates, additions); + return String.format("Remove %"+iwidth+"d, Change %"+iwidth+"d, CompatChange %"+iwidth+"d, Deprecate %"+iwidth+"d, Add %"+iwidth+"d", + removes, changes, compatChanges, deprecates, additions); } } diff --git a/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java b/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java index a2b8ae9..8f7fb22 100755 --- a/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java +++ b/api/src/main/java/org/semver/jardiff/DifferenceAccumulatingHandler.java @@ -32,6 +32,7 @@ import org.osjava.jardiff.MethodInfo; import org.semver.Delta; import org.semver.Delta.Add; import org.semver.Delta.Change; +import org.semver.Delta.CompatChange; import org.semver.Delta.Deprecate; import org.semver.Delta.Difference; import org.semver.Delta.Remove; @@ -167,6 +168,15 @@ public final class DifferenceAccumulatingHandler extends AbstractDiffHandler { this.differences.add(new Change(getCurrentClassName(), oldFieldInfo, newFieldInfo)); } + @Override + public void fieldChangedCompat(final FieldInfo oldFieldInfo, final FieldInfo newFieldInfo) throws DiffException { + if (!isClassConsidered(getCurrentClassName())) { + return; + } + + this.differences.add(new CompatChange(getCurrentClassName(), oldFieldInfo, newFieldInfo)); + } + @Override public void fieldDeprecated(final FieldInfo oldFieldInfo, final FieldInfo newFieldInfo) throws DiffException { if (!isClassConsidered(getCurrentClassName())) { @@ -185,6 +195,15 @@ public final class DifferenceAccumulatingHandler extends AbstractDiffHandler { this.differences.add(new Change(getCurrentClassName(), oldMethodInfo, newMethodInfo)); } + @Override + public void methodChangedCompat(final MethodInfo oldMethodInfo, final MethodInfo newMethodInfo) throws DiffException { + if (!isClassConsidered(getCurrentClassName())) { + return; + } + + this.differences.add(new CompatChange(getCurrentClassName(), oldMethodInfo, newMethodInfo)); + } + @Override public void methodDeprecated(final MethodInfo oldMethodInfo, final MethodInfo newMethodInfo) throws DiffException { if (!isClassConsidered(getCurrentClassName())) { -- cgit v1.2.3