aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Eluard <[email protected]>2013-07-07 04:03:29 -0700
committerJulien Eluard <[email protected]>2013-07-07 04:03:29 -0700
commit941c16dbe976c4acfa5faa24214e351b56b58791 (patch)
tree6ef0d90f3018b927c0c2a56f6aff0d76a4d1981f
parente43dd9d0d77698758655524005653bdce6d0ad93 (diff)
parent95a8f35e037fe8498df3904e47e74d639c1d1a31 (diff)
Merge pull request #12 from tesla/master
Integrating JarDiff source
-rwxr-xr-xapi/pom.xml14
-rw-r--r--api/src/main/java/org/osjava/jardiff/AbstractDiffHandler.java68
-rw-r--r--api/src/main/java/org/osjava/jardiff/AbstractInfo.java316
-rw-r--r--api/src/main/java/org/osjava/jardiff/ClassInfo.java159
-rw-r--r--api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java146
-rw-r--r--api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java722
-rw-r--r--api/src/main/java/org/osjava/jardiff/DiffCriteria.java92
-rw-r--r--api/src/main/java/org/osjava/jardiff/DiffException.java57
-rw-r--r--api/src/main/java/org/osjava/jardiff/DiffHandler.java263
-rw-r--r--api/src/main/java/org/osjava/jardiff/FieldInfo.java106
-rw-r--r--api/src/main/java/org/osjava/jardiff/JarDiff.java489
-rw-r--r--api/src/main/java/org/osjava/jardiff/MethodInfo.java105
-rw-r--r--api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java159
-rw-r--r--api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java784
-rw-r--r--api/src/main/java/org/osjava/jardiff/Tools.java80
15 files changed, 3557 insertions, 3 deletions
diff --git a/api/pom.xml b/api/pom.xml
index 53e0855..a800ad6 100755
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -20,11 +20,19 @@
<version>2.0.0</version>
</dependency>
<dependency>
- <groupId>jardiff</groupId>
- <artifactId>jardiff</artifactId>
- <version>0.2</version>
+ <groupId>asm</groupId>
+ <artifactId>asm</artifactId>
</dependency>
<dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-commons</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
<groupId>de.tototec</groupId>
<artifactId>de.tototec.cmdoption</artifactId>
<version>0.2.0</version>
diff --git a/api/src/main/java/org/osjava/jardiff/AbstractDiffHandler.java b/api/src/main/java/org/osjava/jardiff/AbstractDiffHandler.java
new file mode 100644
index 0000000..2c06906
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/AbstractDiffHandler.java
@@ -0,0 +1,68 @@
+/*
+ * org.osjava.jardiff.AbstractDiffHandler
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * An abstract implementation of DiffHandler which provides utility methods.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public abstract class AbstractDiffHandler implements DiffHandler
+{
+ /**
+ * Get the java classname given the internal class name internalName.
+ *
+ * @return the classname for internalName
+ */
+ protected final String getClassName(String internalName) {
+ StringBuffer ret = new StringBuffer(internalName.length());
+ for (int i = 0; i < internalName.length(); i++) {
+ char ch = internalName.charAt(i);
+ switch (ch) {
+ case '$':
+ case '/':
+ ret.append('.');
+ break;
+ default:
+ ret.append(ch);
+ }
+ }
+ return ret.toString();
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/AbstractInfo.java b/api/src/main/java/org/osjava/jardiff/AbstractInfo.java
new file mode 100644
index 0000000..197752c
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/AbstractInfo.java
@@ -0,0 +1,316 @@
+/*
+ * org.osjava.jardiff.AbstractInfo
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+import org.objectweb.asm.Opcodes;
+
+/**
+ * An abstract class representing information about a class, method or field.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public abstract class AbstractInfo
+{
+ /**
+ * The string used to represent a class, method or field with public
+ * access.
+ */
+ public final String ACCESS_PUBLIC = "public";
+
+ /**
+ * The string used to represent a class, method or field with protected
+ * access.
+ */
+ public final String ACCESS_PROTECTED = "protected";
+
+ /**
+ * The string used to represent a class, method or field with package
+ * private access.
+ * Package private access is the default access level used by java when
+ * you do not specify one of public, protected or private.
+ */
+ public final String ACCESS_PACKAGE = "package";
+
+ /**
+ * The string used to represent a class, method or field with private
+ * access.
+ */
+ public final String ACCESS_PRIVATE = "private";
+
+ /**
+ * The access flags for this class, method or field.
+ */
+ private final int access;
+
+ /**
+ * The internal name of this class, method or field.
+ */
+ private final String name;
+
+ /**
+ * Construct a new AbstractInfo with the specified access and name.
+ *
+ * @param access The access flags for this class, method or field.
+ * @param name The internal name of this class, method or field.
+ */
+ public AbstractInfo(int access, String name) {
+ this.access = access;
+ this.name = name;
+ }
+
+ /**
+ * Get the access flags for this class, method or field.
+ *
+ * @return the access flags.
+ */
+ public final int getAccess() {
+ return access;
+ }
+
+ /**
+ * Get the internal name of this class, method or field.
+ *
+ * @return the name
+ */
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * Test if this class, method or field is public.
+ *
+ * @return true if it is public.
+ */
+ public final boolean isPublic() {
+ return (access & Opcodes.ACC_PUBLIC) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is protected.
+ *
+ * @return true if it is protected.
+ */
+ public final boolean isProtected() {
+ return (access & Opcodes.ACC_PROTECTED) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is package private.
+ *
+ * @return true if it is package private.
+ */
+ public final boolean isPackagePrivate() {
+ return (access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED |
+ Opcodes.ACC_PRIVATE)) == 0;
+ }
+
+ /**
+ * Test if this class, method or field is private.
+ *
+ * @return true if it is private.
+ */
+ public final boolean isPrivate() {
+ return (access & Opcodes.ACC_PRIVATE) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is abstract.
+ *
+ * @return true if it is abstract.
+ */
+ public final boolean isAbstract() {
+ return (access & Opcodes.ACC_ABSTRACT) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is annotation
+ *
+ * @return true if it is annotation.
+ */
+ public final boolean isAnnotation() {
+ return (access & Opcodes.ACC_ANNOTATION) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is a bridge
+ *
+ * @return true if it is a bridge.
+ */
+ public final boolean isBridge() {
+ return (access & Opcodes.ACC_BRIDGE) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is deprecated.
+ *
+ * @return true if it is deprecated.
+ */
+ public final boolean isDeprecated() {
+ return (access & Opcodes.ACC_DEPRECATED) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is an enum.
+ *
+ * @return true if it is an enum.
+ */
+ public final boolean isEnum() {
+ return (access & Opcodes.ACC_ENUM) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is final.
+ *
+ * @return true if it is final.
+ */
+ public final boolean isFinal() {
+ return (access & Opcodes.ACC_FINAL) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is an interface.
+ *
+ * @return true if it is an interface.
+ */
+ public final boolean isInterface() {
+ return (access & Opcodes.ACC_INTERFACE) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is native.
+ *
+ * @return true if it is native.
+ */
+ public final boolean isNative() {
+ return (access & Opcodes.ACC_NATIVE) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is static.
+ *
+ * @return true if it is static.
+ */
+ public final boolean isStatic() {
+ return (access & Opcodes.ACC_STATIC) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is string.
+ *
+ * @return true if it is strict.
+ */
+ public final boolean isStrict() {
+ return (access & Opcodes.ACC_STRICT) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is super.
+ *
+ * @return true if it is super.
+ */
+ public final boolean isSuper() {
+ return (access & Opcodes.ACC_SUPER) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is synchronized.
+ *
+ * @return true if it is synchronized
+ */
+ public final boolean isSynchronized() {
+ return (access & Opcodes.ACC_SYNCHRONIZED) != 0;
+ }
+
+ /**
+ * Test if this class, method or field is synthetic.
+ *
+ * @return true if it is synchronized.
+ */
+ public final boolean isSynthetic() {
+ return (access & Opcodes.ACC_SYNTHETIC) != 0;
+ }
+
+ /**
+ * Test if this class or field is transient.
+ * If this flag is set on a method it means something different.
+ *
+ * @return true if it is transient.
+ */
+ public final boolean isTransient() {
+ return !(this instanceof MethodInfo) &&
+ ((access & Opcodes.ACC_TRANSIENT) != 0);
+ }
+
+ /**
+ * Test if this method is varargs.
+ * If this flag is set on a class or field it means something different.
+ * Well, it probably shouldn't be set on a class as it would make
+ * no sense, it only really makes sense on fields and methods.
+ *
+ * @return true if it is vargargs.
+ */
+ public final boolean isVarargs() {
+ return (this instanceof MethodInfo) &&
+ ((access & Opcodes.ACC_VARARGS) != 0);
+ }
+
+ /**
+ * Test if this class, method or field is volatile.
+ *
+ * @return true if it is volatile.
+ */
+ public final boolean isVolatile() {
+ return (access & Opcodes.ACC_VOLATILE) != 0;
+ }
+
+ /**
+ * Retrivie the access level for this class, method or field.
+ *
+ * @return the access level
+ */
+ public final String getAccessType() {
+ if (isPublic())
+ return ACCESS_PUBLIC;
+ if (isProtected())
+ return ACCESS_PROTECTED;
+ if (isPrivate())
+ return ACCESS_PRIVATE;
+ return ACCESS_PACKAGE;
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/ClassInfo.java b/api/src/main/java/org/osjava/jardiff/ClassInfo.java
new file mode 100644
index 0000000..d27ccc3
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/ClassInfo.java
@@ -0,0 +1,159 @@
+/*
+ * org.osjava.jardiff.ClassInfo
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+import java.util.Map;
+
+/**
+ * Information about a class file.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public final class ClassInfo extends AbstractInfo
+{
+ /**
+ * The classfile version number.
+ */
+ private int version;
+
+ /**
+ * The class signature.
+ */
+ private String signature;
+
+ /**
+ * The internal classname of the superclass.
+ */
+ private String supername;
+
+ /**
+ * An array of names of internal classnames of interfaces implmented
+ * by the class.
+ */
+ private String[] interfaces;
+
+ /**
+ * A map of method signature to MethodInfo, for the methods provided
+ * by this class.
+ */
+ private Map methodMap;
+
+ /**
+ * A map of field signature to FieldInfo, for the fields provided by
+ * this class.
+ */
+ private Map fieldMap;
+
+ /**
+ * Create a new classinfo.
+ *
+ * @param version the class file version number.
+ * @param access the access flags for the class.
+ * @param name the internal name of the class.
+ * @param signature the signature of the class.
+ * @param interfaces an array of internal names of interfaces implemented
+ * by the class.
+ * @param methodMap a map of methods provided by this class.
+ * @param fieldMap a map of fields provided by this class.
+ */
+ public ClassInfo(int version, int access, String name, String signature,
+ String supername, String[] interfaces, Map methodMap,
+ Map fieldMap) {
+ super(access, name);
+ this.version = version;
+ this.signature = signature;
+ this.supername = supername;
+ this.interfaces = interfaces;
+ this.methodMap = methodMap;
+ this.fieldMap = fieldMap;
+ }
+
+ /**
+ * Get the class file version.
+ *
+ * @return The class file version as specified in the java language spec.
+ */
+ public final int getVersion() {
+ return version;
+ }
+
+ /**
+ * Get the class signature.
+ *
+ * @return the class signature
+ */
+ public final String getSignature() {
+ return signature;
+ }
+
+ /**
+ * Get the internal name of the superclass.
+ *
+ * @return the internal name of the superclass
+ */
+ public final String getSupername() {
+ return supername;
+ }
+
+ /**
+ * Get the internal names of the interfaces implemented by this class
+ *
+ * @return an array of internal names of classes implemented by the class.
+ */
+ public final String[] getInterfaces() {
+ return interfaces;
+ }
+
+ /**
+ * Get the map of method signatures to methods.
+ *
+ * @return a map with method signatures as keys, and MethodInfos as values.
+ */
+ public final Map getMethodMap() {
+ return methodMap;
+ }
+
+ /**
+ * Get the map of field signatures to fields.
+ *
+ * @return a map with field signatures as keys, and FieldInfos as values.
+ */
+ public final Map getFieldMap() {
+ return fieldMap;
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java b/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java
new file mode 100644
index 0000000..a97885d
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java
@@ -0,0 +1,146 @@
+/*
+ * org.osjava.jardiff.ClassInfoVisitor
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * A reusable class which uses the ASM to build up ClassInfo about a
+ * java class file.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class ClassInfoVisitor extends EmptyVisitor
+{
+ /**
+ * The class file version.
+ */
+ private int version;
+
+ /**
+ * The access flags for the class.
+ */
+
+ private int access;
+
+ /**
+ * The internal name of the class.
+ */
+ private String name;
+
+ /**
+ * The signature of the class
+ */
+ private String signature;
+
+ /**
+ * The internal name of the superclass.
+ */
+ private String supername;
+
+ /**
+ * An array of internal names of interfaces implemented by this class.
+ */
+ private String[] interfaces;
+
+ /**
+ * A map of method signature to a MethodInfo describing the method.
+ */
+ private Map methodMap;
+
+ /**
+ * A map of field signature to a FieldInfo describing the field.
+ */
+ private Map fieldMap;
+
+ /**
+ * Reset this ClassInfoVisitor so that it can be used to visit another
+ * class.
+ */
+ public void reset() {
+ methodMap = new HashMap();
+ fieldMap = new HashMap();
+ }
+
+ /**
+ * The the classInfo this ClassInfoVisitor has built up about a class
+ */
+ public ClassInfo getClassInfo() {
+ return new ClassInfo(version, access, name, signature, supername,
+ interfaces, methodMap, fieldMap);
+ }
+
+ /**
+ * Receive notification of information about a class from ASM.
+ *
+ * @param version the class file version number.
+ * @param access the access flags for the class.
+ * @param name the internal name of the class.
+ * @param signature the signature of the class.
+ * @param supername the internal name of the super class.
+ * @param interfaces the internal names of interfaces implemented.
+ */
+ public void visit(int version, int access, String name, String signature,
+ String supername, String[] interfaces) {
+ this.version = version;
+ this.access = access;
+ this.name = name;
+ this.signature = signature;
+ this.supername = supername;
+ this.interfaces = interfaces;
+ }
+
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ methodMap.put(name + desc, new MethodInfo(access, name, desc,
+ signature, exceptions));
+ return null;
+ }
+
+ public FieldVisitor visitField(int access, String name, String desc,
+ String signature, Object value) {
+ fieldMap.put(name,
+ new FieldInfo(access, name, desc, signature, value));
+ return this;
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java b/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java
new file mode 100644
index 0000000..1c5b016
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/DOMDiffHandler.java
@@ -0,0 +1,722 @@
+/*
+ * org.osjava.jardiff.DOMDiffHandler
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/jardiff/src/ava/org/osjava/jardiff/DOMDiffHandler.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/* Not in 1.4.2
+import javax.xml.XMLConstants;
+*/
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.Result;
+import org.w3c.dom.*;
+
+import org.objectweb.asm.Type;
+
+/**
+ * A specific type of DiffHandler which uses DOM to create an XML document
+ * describing the changes in the diff.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class DOMDiffHandler implements DiffHandler
+{
+ /**
+ * The XML namespace used.
+ */
+ public static final String XML_URI = "http://www.osjava.org/jardiff/0.1";
+
+ /**
+ * The javax.xml.transform.sax.Transformer used to convert
+ * the DOM to text.
+ */
+ private final Transformer transformer;
+
+ /**
+ * Where we write the result to.
+ */
+ private final Result result;
+
+ /**
+ * The document object we're building
+ */
+ private final Document doc;
+
+ /**
+ * The current Node.
+ */
+ private Node currentNode;
+
+ /**
+ * Create a new DOMDiffHandler which writes to System.out
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public DOMDiffHandler() throws DiffException {
+ try {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ this.transformer = tf.newTransformer();
+ this.result = new StreamResult(System.out);
+ this.currentNode = null;
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ this.doc = db.newDocument();
+ } catch (TransformerConfigurationException tce) {
+ throw new DiffException(tce);
+ } catch (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
+ * the output in a flexible manner, allowing a stylesheet to be specified
+ * and some result object.
+ *
+ * @param transformer The transformer to transform the output with.
+ * @param result Where to put the result.
+ */
+ public DOMDiffHandler(Transformer transformer, Result result)
+ throws DiffException
+ {
+ try {
+ this.transformer = transformer;
+ this.result = result;
+ this.currentNode = null;
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ this.doc = db.newDocument();
+ } catch (ParserConfigurationException pce) {
+ throw new DiffException(pce);
+ }
+ }
+
+ /**
+ * Start the diff.
+ * This writes out the start of a &lt;diff&gt; node.
+ *
+ * @param oldJar ignored
+ * @param newJar ignored
+ * @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");
+ tmp.setAttribute( "old", oldJar);
+ tmp.setAttribute( "new", newJar);
+ doc.appendChild(tmp);
+ currentNode = tmp;
+ }
+
+ /**
+ * Start the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startOldContents() throws DiffException {
+ Element tmp = doc.createElementNS(XML_URI, "oldcontents");
+ currentNode.appendChild(tmp);
+ currentNode = tmp;
+ }
+
+ /**
+ * Start the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startNewContents() throws DiffException {
+ Element tmp = doc.createElementNS(XML_URI, "newcontents");
+ currentNode.appendChild(tmp);
+ currentNode = tmp;
+ }
+
+ /**
+ * Add a contained class.
+ *
+ * @param info information about a class
+ * @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");
+ tmp.setAttribute("name", info.getName());
+ currentNode.appendChild(tmp);
+ }
+
+ /**
+ * End the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endOldContents() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * End the list of new contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endNewContents() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * Start the removed node.
+ * This writes out a &lt;removed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startRemoved() throws DiffException {
+ 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
+ *
+ * @param info The info to write out.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classRemoved(ClassInfo info) throws DiffException {
+ writeClassInfo(info);
+ }
+
+ /**
+ * End the removed section.
+ * This closes the &lt;removed&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endRemoved() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * Start the added section.
+ * This opens the &lt;added&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startAdded() throws DiffException {
+ 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.
+ *
+ * @param info The class info describing the added class.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classAdded(ClassInfo info) throws DiffException {
+ writeClassInfo(info);
+ }
+
+ /**
+ * End the added section.
+ * This closes the &lt;added&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endAdded() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * Start the changed section.
+ * This writes out the &lt;changed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startChanged() throws DiffException {
+ Element tmp = doc.createElementNS(XML_URI, "changed");
+ currentNode.appendChild(tmp);
+ currentNode = tmp;
+ }
+
+ /**
+ * Start a changed section for an individual class.
+ * This writes out an &lt;classchanged&gt; node with the real class
+ * name as the name attribute.
+ *
+ * @param internalName the internal name of the class that has changed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startClassChanged(String internalName) throws DiffException
+ {
+ 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
+ * removed section.
+ *
+ * @param info Info about the field that's been removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void fieldRemoved(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
+ * 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 {
+ writeMethodInfo(info);
+ }
+
+ /**
+ * Write out info about an added field.
+ * 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 {
+ writeFieldInfo(info);
+ }
+
+ /**
+ * Write out info about a added method.
+ * This just writes out the method info, it will be inside a start/end
+ * added section.
+ *
+ * @param info Info about the added method.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void methodAdded(MethodInfo info) throws DiffException {
+ writeMethodInfo(info);
+ }
+
+ /**
+ * Write out info aboout a changed class.
+ * This writes out a &lt;classchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the class
+ * followed by a &lt;to&gt; node with the new information about the
+ * class.
+ *
+ * @param oldInfo Info about the old class.
+ * @param newInfo Info about the new class.
+ * @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
+ {
+ 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");
+ tmp.appendChild(from);
+ tmp.appendChild(to);
+ currentNode.appendChild(tmp);
+ this.currentNode = from;
+ writeClassInfo(oldInfo);
+ this.currentNode = to;
+ writeClassInfo(newInfo);
+ this.currentNode = currentNode;
+ }
+
+ /**
+ * Write out info aboout a changed field.
+ * This writes out a &lt;fieldchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the field
+ * followed by a &lt;to&gt; 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(FieldInfo oldInfo, 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");
+ 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 aboout a changed method.
+ * This writes out a &lt;methodchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the method
+ * followed by a &lt;to&gt; 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 methodChanged(MethodInfo oldInfo, 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");
+ tmp.appendChild(from);
+ tmp.appendChild(to);
+ currentNode.appendChild(tmp);
+ this.currentNode = from;
+ writeMethodInfo(oldInfo);
+ this.currentNode = to;
+ writeMethodInfo(newInfo);
+ this.currentNode = currentNode;
+ }
+
+ /**
+ * End the changed section for an individual class.
+ * This closes the &lt;classchanged&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endClassChanged() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * End the changed section.
+ * This closes the &lt;changed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endChanged() throws DiffException {
+ currentNode = currentNode.getParentNode();
+ }
+
+ /**
+ * End the diff.
+ * This closes the &lt;diff&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endDiff() throws DiffException {
+ DOMSource source = new DOMSource(doc);
+ try {
+ transformer.transform(source, result);
+ } catch (TransformerException te) {
+ throw new DiffException(te);
+ }
+ }
+
+ /**
+ * Write out information about a class.
+ * This writes out a &lt;class&gt; node, which contains information about
+ * what interfaces are implemented each in a &lt;implements&gt; node.
+ *
+ * @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");
+ currentNode.appendChild(tmp);
+ this.currentNode = tmp;
+ addAccessFlags(info);
+ if (info.getName() != null)
+ tmp.setAttribute( "name",
+ info.getName());
+ if (info.getSignature() != null)
+ tmp.setAttribute( "signature",
+ info.getSignature());
+ if (info.getSupername() != null)
+ tmp.setAttribute( "superclass",
+ info.getSupername());
+ String[] interfaces = info.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ Element iface = doc.createElementNS(XML_URI, "implements");
+ tmp.appendChild(iface);
+ iface.setAttribute( "name",
+ interfaces[i]);
+ }
+ this.currentNode = currentNode;
+ }
+
+ /**
+ * Write out information about a method.
+ * This writes out a &lt;method&gt; node which contains information about
+ * 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");
+ currentNode.appendChild(tmp);
+ this.currentNode = tmp;
+ addAccessFlags(info);
+
+ if (info.getName() != null)
+ tmp.setAttribute( "name", info.getName());
+ if (info.getSignature() != null)
+ tmp.setAttribute( "signature", info.getSignature());
+ if (info.getDesc() != null)
+ addMethodNodes(info.getDesc());
+ String[] exceptions = info.getExceptions();
+ if (exceptions != null) {
+ for (int i = 0; i < exceptions.length; i++) {
+ 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 &lt;field&gt; node with attributes describing the
+ * field.
+ *
+ * @param info Info about the field.
+ */
+ protected void writeFieldInfo(FieldInfo info) {
+ Node currentNode = this.currentNode;
+ Element tmp = doc.createElementNS(XML_URI, "field");
+ currentNode.appendChild(tmp);
+ this.currentNode = tmp;
+ addAccessFlags(info);
+
+ if (info.getName() != null)
+ tmp.setAttribute( "name",
+ info.getName());
+ if (info.getSignature() != null)
+ tmp.setAttribute( "signature",
+ info.getSignature());
+ if (info.getValue() != null)
+ tmp.setAttribute( "value",
+ info.getValue().toString());
+ if (info.getDesc() != null)
+ addTypeNode(info.getDesc());
+ this.currentNode = currentNode;
+ }
+
+ /**
+ * Add attributes describing some access flags.
+ * This adds the attributes to the attr field.
+ *
+ * @see #attr
+ * @param info Info describing the access flags.
+ */
+ protected void addAccessFlags(AbstractInfo info) {
+ Element currentNode = (Element) this.currentNode;
+ currentNode.setAttribute( "access", info.getAccessType());
+ if (info.isAbstract())
+ currentNode.setAttribute( "abstract", "yes");
+ if (info.isAnnotation())
+ currentNode.setAttribute( "annotation", "yes");
+ if (info.isBridge())
+ currentNode.setAttribute( "bridge", "yes");
+ if (info.isDeprecated())
+ currentNode.setAttribute( "deprecated", "yes");
+ if (info.isEnum())
+ currentNode.setAttribute( "enum", "yes");
+ if (info.isFinal())
+ currentNode.setAttribute( "final", "yes");
+ if (info.isInterface())
+ currentNode.setAttribute( "interface", "yes");
+ if (info.isNative())
+ currentNode.setAttribute( "native", "yes");
+ if (info.isStatic())
+ currentNode.setAttribute( "static", "yes");
+ if (info.isStrict())
+ currentNode.setAttribute( "strict", "yes");
+ if (info.isSuper())
+ currentNode.setAttribute( "super", "yes");
+ if (info.isSynchronized())
+ currentNode.setAttribute( "synchronized", "yes");
+ if (info.isSynthetic())
+ currentNode.setAttribute( "synthetic", "yes");
+ if (info.isTransient())
+ currentNode.setAttribute( "transient", "yes");
+ if (info.isVarargs())
+ currentNode.setAttribute( "varargs", "yes");
+ if (info.isVolatile())
+ currentNode.setAttribute( "volatile", "yes");
+ }
+
+ /**
+ * Add the method nodes for the method descriptor.
+ * This writes out an &lt;arguments&gt; node containing the
+ * argument types for the method, followed by a &lt;return&gt; 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;
+ Element tmp = doc.createElementNS(XML_URI,"arguments");
+ currentNode.appendChild(tmp);
+ this.currentNode = tmp;
+ for (int i = 0; i < args.length; i++)
+ addTypeNode(args[i]);
+ tmp = doc.createElementNS(XML_URI,"return");
+ currentNode.appendChild(tmp);
+ this.currentNode = tmp;
+ addTypeNode(ret);
+ this.currentNode = currentNode;
+ }
+
+ /**
+ * Add a type node for the specified descriptor.
+ *
+ * @param desc A type descriptor.
+ */
+ protected void addTypeNode(String desc) {
+ addTypeNode(Type.getType(desc));
+ }
+
+ /**
+ * Add a type node for the specified type.
+ * This writes out a &lt;type&gt; node with attributes describing
+ * the type.
+ *
+ * @param type The type to describe.
+ */
+ protected void addTypeNode(Type type) {
+ Element tmp = doc.createElementNS(XML_URI, "type");
+ currentNode.appendChild(tmp);
+ int i = type.getSort();
+ if (i == Type.ARRAY) {
+ tmp.setAttribute( "array", "yes");
+ tmp.setAttribute( "dimensions",
+ "" + type.getDimensions());
+ type = type.getElementType();
+ i = type.getSort();
+ }
+ switch (i) {
+ case Type.BOOLEAN:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "boolean");
+ break;
+ case Type.BYTE:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "byte");
+ break;
+ case Type.CHAR:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "char");
+ break;
+ case Type.DOUBLE:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "double");
+ break;
+ case Type.FLOAT:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "float");
+ break;
+ case Type.INT:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "int");
+ break;
+ case Type.LONG:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "long");
+ break;
+ case Type.OBJECT:
+ tmp.setAttribute( "name", type.getInternalName());
+ break;
+ case Type.SHORT:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "short");
+ break;
+ case Type.VOID:
+ tmp.setAttribute( "primitive", "yes");
+ tmp.setAttribute( "name", "void");
+ break;
+ }
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/DiffCriteria.java b/api/src/main/java/org/osjava/jardiff/DiffCriteria.java
new file mode 100644
index 0000000..b235405
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/DiffCriteria.java
@@ -0,0 +1,92 @@
+/*
+ * org.osjava.jardiff.DiffCriteria
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * An interface for choosing which API differences are interesting.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public interface DiffCriteria
+{
+ /**
+ * Check if the class described by classinfo is interesting.
+ *
+ * @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
+ * 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.
+ *
+ * @return true if the changes are interesting, false otherwise.
+ */
+ public boolean differs(MethodInfo methodinfo, MethodInfo methodinfo_1_);
+
+ /**
+ * Check if the differences between the field described by infoA and the
+ * field described by infoB are interesting.
+ *
+ * @return true if the changes are interesting, false otherwise.
+ */
+ public boolean differs(FieldInfo fieldinfo, FieldInfo fieldinfo_2_);
+}
diff --git a/api/src/main/java/org/osjava/jardiff/DiffException.java b/api/src/main/java/org/osjava/jardiff/DiffException.java
new file mode 100644
index 0000000..8ddf529
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/DiffException.java
@@ -0,0 +1,57 @@
+/*
+ * org.osjava.jardiff.DiffException
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * A wrapper exception classes for various exceptions that can happen
+ * whilst performing a diff.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class DiffException extends Exception
+{
+ /**
+ * Create a new DiffException wrapping another exception.
+ *
+ * @param toWrap the wrapped exception
+ */
+ public DiffException(Exception toWrap) {
+ super((Throwable) toWrap);
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/DiffHandler.java b/api/src/main/java/org/osjava/jardiff/DiffHandler.java
new file mode 100644
index 0000000..92eadcd
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/DiffHandler.java
@@ -0,0 +1,263 @@
+/*
+ * org.osjava.jardiff.DiffHandler
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * An interface for classes which wish to receive information about
+ * differences in class files between two different jar file version to
+ * implement.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+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.
+ * writing to a file caused an IOException
+ */
+ public void startDiff(String a, String b)
+ throws DiffException;
+
+ /**
+ * Start the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startOldContents() throws DiffException;
+
+ /**
+ * Start the list of new contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startNewContents() throws DiffException;
+
+ /**
+ * Add a contained class.
+ *
+ * @param info information about a class
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void contains(ClassInfo info) throws DiffException;
+
+ /**
+ * End the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endOldContents() throws DiffException;
+
+ /**
+ * End the list of new contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endNewContents() throws DiffException;
+
+ /**
+ * Start the list of removed classes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startRemoved() throws DiffException;
+
+ /**
+ * Notification that a class was removed.
+ *
+ * @param classinfo information about the class that has been removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classRemoved(ClassInfo classinfo) throws DiffException;
+
+ /**
+ * End of list of removed classes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endRemoved() throws DiffException;
+
+ /**
+ * Start of list of added classes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startAdded() throws DiffException;
+
+ /**
+ * Notification that a class was added.
+ *
+ * @param classinfo information about the class that has been removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classAdded(ClassInfo classinfo) throws DiffException;
+
+ /**
+ * End of list of removed classes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endAdded() throws DiffException;
+
+ /**
+ * Start list of changed classes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startChanged() throws DiffException;
+
+ /**
+ * Start information about class changes for the classname passed.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * 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.
+ *
+ * @param fieldinfo Information about the field removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * 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.
+ *
+ * @param methodinfo Information about the method removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * 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.
+ *
+ * @param fieldinfo Information about the field added.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * 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.
+ *
+ * @param methodinfo Information about the method added.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * 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
+ * flags have changed.
+ *
+ * @param oldClassinfo Information about the old class.
+ * @param newClassinfo Information about the new class.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classChanged(ClassInfo oldClassinfo, ClassInfo newClassinfo)
+ throws DiffException;
+
+ /**
+ * A field on the current class has changed.
+ *
+ * @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 fieldChanged(FieldInfo oldFieldinfo, FieldInfo newFieldinfo)
+ throws DiffException;
+
+ /**
+ * A method on the current class has changed.
+ *
+ * @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 methodChanged
+ (MethodInfo oldMethodInfo, MethodInfo newMethodInfo) throws DiffException;
+
+ /**
+ * End of changes for the current class.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endClassChanged() throws DiffException;
+
+ /**
+ * End of class changes.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endChanged() throws DiffException;
+
+ /**
+ * End of the diff.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endDiff() throws DiffException;
+}
diff --git a/api/src/main/java/org/osjava/jardiff/FieldInfo.java b/api/src/main/java/org/osjava/jardiff/FieldInfo.java
new file mode 100644
index 0000000..d319aea
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/FieldInfo.java
@@ -0,0 +1,106 @@
+/*
+ * org.osjava.jardiff.FieldInfo
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * Information about a field of a class.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public final class FieldInfo extends AbstractInfo
+{
+ /**
+ * The field descriptor for this field.
+ */
+ private String desc;
+
+ /**
+ * The signature for this field.
+ */
+ private String signature;
+
+ /**
+ * The initial value of this field.
+ */
+ private Object value;
+
+ /**
+ * Create a new FieldInfo
+ *
+ * @param access The access flags.
+ * @param name The name of the field.
+ * @param desc The field discriptor.
+ * @param signature The signature of this field.
+ * @param value The initial value of the field.
+ */
+ public FieldInfo(int access, String name, String desc, String signature,
+ Object value) {
+ super(access, name);
+ this.desc = desc;
+ this.signature = signature;
+ this.value = value;
+ }
+
+ /**
+ * Get the descriptor for this FieldInfo.
+ *
+ * @return The field descriptor.
+ */
+ public final String getDesc() {
+ return desc;
+ }
+
+ /**
+ * Get the signature for this fieldinfo.
+ *
+ * @return The signature.
+ */
+ public final String getSignature() {
+ return signature;
+ }
+
+ /**
+ * Get the initial value for this fieldinfo
+ *
+ * @return The initial value.
+ */
+ public final Object getValue() {
+ return value;
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/JarDiff.java b/api/src/main/java/org/osjava/jardiff/JarDiff.java
new file mode 100644
index 0000000..21eb333
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/JarDiff.java
@@ -0,0 +1,489 @@
+/*
+ * org.osjava.jardiff.JarDiff
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.TreeMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+/*
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+*/
+
+import org.objectweb.asm.ClassReader;
+
+/**
+ * A class to perform a diff between two jar files.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class JarDiff
+{
+ /**
+ * A map containing information about classes which are dependencies.
+ * Keys are internal class names.
+ * Values are instances of ClassInfo.
+ */
+ protected Map depClassInfo = new HashMap();
+
+ /**
+ * A map containing information about classes in the old jar file.
+ * Keys are internal class names.
+ * Values are instances of ClassInfo.
+ */
+ protected Map oldClassInfo = new TreeMap();
+
+ /**
+ * A map containing information about classes in the new jar file.
+ * Keys are internal class names.
+ * Values are instances of ClassInfo.
+ */
+ protected Map newClassInfo = new TreeMap();
+
+ /**
+ * An array of dependencies which are jar files, or urls.
+ */
+ private URL[] deps;
+
+ /**
+ * A class loader used for loading dependency classes.
+ */
+ private URLClassLoader depLoader;
+
+ /**
+ * The name of the old version.
+ */
+ private String oldVersion;
+
+ /**
+ * The name of the new version.
+ */
+ private String newVersion;
+
+ /**
+ * Class info visitor, used to load information about classes.
+ */
+ private ClassInfoVisitor infoVisitor = new ClassInfoVisitor();
+
+ /**
+ * Create a new JarDiff object.
+ */
+ public JarDiff() {
+ }
+
+ /**
+ * Set the name of the old version.
+ *
+ * @param oldVersion the name
+ */
+ public void setOldVersion(String oldVersion) {
+ this.oldVersion = oldVersion;
+ }
+
+ /**
+ * Get the name of the old version.
+ *
+ * @return the name
+ */
+ public String getOldVersion() {
+ return oldVersion;
+ }
+
+ /**
+ * Set the name of the new version.
+ *
+ * @param newVersion
+ */
+ public void setNewVersion(String newVersion) {
+ this.newVersion = newVersion;
+ }
+
+ /**
+ * Get the name of the new version.
+ *
+ * @return the name
+ */
+ public String getNewVersion() {
+ return newVersion;
+ }
+
+ /**
+ * Set the dependencies.
+ *
+ * @param deps an array of urls pointing to jar files or directories
+ * containing classes which are required dependencies.
+ */
+ public void setDependencies(URL[] deps) {
+ this.deps = deps;
+ }
+
+ /**
+ * Get the dependencies.
+ *
+ * @return the dependencies as an array of URLs
+ */
+ public URL[] getDependencies() {
+ return deps;
+ }
+
+ /**
+ * Load classinfo given a ClassReader.
+ *
+ * @param reader the ClassReader
+ * @return the ClassInfo
+ */
+ private synchronized ClassInfo loadClassInfo(ClassReader reader)
+ throws IOException
+ {
+ infoVisitor.reset();
+ reader.accept(infoVisitor, false);
+ return infoVisitor.getClassInfo();
+ }
+
+ /**
+ * Load all the classes from the specified URL and store information
+ * about them in the specified map.
+ * This currently only works for jar files, <b>not</b> directories
+ * which contain classes in subdirectories or in the current directory.
+ *
+ * @param infoMap the map to store the ClassInfo in.
+ * @throws DiffException if there is an exception reading info about a
+ * class.
+ */
+ private void loadClasses(Map infoMap, URL path) throws DiffException {
+ try {
+ File jarFile = null;
+ if(!"file".equals(path.getProtocol()) || path.getHost() != null) {
+ // If it's not a local file, store it as a temporary jar file.
+ // java.util.jar.JarFile requires a local file handle.
+ 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];
+ int i;
+ while( (i = in.read(buffer,0,buffer.length)) != -1) {
+ out.write(buffer, 0, i);
+ }
+ in.close();
+ out.close();
+ } else {
+ // Else it's a local file, nothing special to do.
+ jarFile = new File(path.getPath());
+ }
+ loadClasses(infoMap, jarFile);
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Load all the classes from the specified URL and store information
+ * about them in the specified map.
+ * This currently only works for jar files, <b>not</b> directories
+ * which contain classes in subdirectories or in the current directory.
+ *
+ * @param infoMap the map to store the ClassInfo in.
+ * @param file the jarfile to load classes from.
+ * @throws IOException if there is an IOException reading info about a
+ * class.
+ */
+ private void loadClasses(Map infoMap, File file) throws DiffException {
+ try {
+ JarFile jar = new JarFile(file);
+ Enumeration e = jar.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = (JarEntry) e.nextElement();
+ String name = entry.getName();
+ if (!entry.isDirectory() && name.endsWith(".class")) {
+ ClassReader reader
+ = new ClassReader(jar.getInputStream(entry));
+ ClassInfo ci = loadClassInfo(reader);
+ infoMap.put(ci.getName(), ci);
+ }
+ }
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Load old classes from the specified URL.
+ *
+ * @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 {
+ loadClasses(oldClassInfo, loc);
+ }
+
+ /**
+ * Load new classes from the specified URL.
+ *
+ * @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 {
+ loadClasses(newClassInfo, loc);
+ }
+
+ /**
+ * Load old classes from the specified File.
+ *
+ * @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 {
+ loadClasses(oldClassInfo, file);
+ }
+
+ /**
+ * Load new classes from the specified File.
+ *
+ * @param file The location of a jar file to load classes from.
+ * @throws DiffExeption if there is an IOException
+ */
+ public void loadNewClasses(File file) throws DiffException {
+ loadClasses(newClassInfo, file);
+ }
+
+ /**
+ * Perform a diff sending the output to the specified handler, using
+ * the specified criteria to select diffs.
+ *
+ * @param handler The handler to receive and handle differences.
+ * @param criteria The criteria we use to select differences.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void diff(DiffHandler handler, DiffCriteria criteria)
+ throws DiffException
+ {
+ // TODO: Build the name from the MANIFEST rather than the filename
+ handler.startDiff(oldVersion, newVersion);
+ Iterator i;
+
+ handler.startOldContents();
+ i = oldClassInfo.entrySet().iterator();
+ while(i.hasNext()) {
+ Map.Entry entry = (Map.Entry) i.next();
+ ClassInfo ci = (ClassInfo) entry.getValue();
+ if(criteria.validClass(ci)) {
+ handler.contains(ci);
+ }
+ }
+ handler.endOldContents();
+
+ handler.startNewContents();
+ i = newClassInfo.entrySet().iterator();
+ while(i.hasNext()) {
+ Map.Entry entry = (Map.Entry) i.next();
+ ClassInfo ci = (ClassInfo) entry.getValue();
+ if(criteria.validClass(ci)) {
+ handler.contains(ci);
+ }
+ }
+ handler.endNewContents();
+
+ java.util.Set onlyOld = new TreeSet(oldClassInfo.keySet());
+ java.util.Set onlyNew = new TreeSet(newClassInfo.keySet());
+ java.util.Set both = new TreeSet(oldClassInfo.keySet());
+ onlyOld.removeAll(newClassInfo.keySet());
+ onlyNew.removeAll(oldClassInfo.keySet());
+ both.retainAll(newClassInfo.keySet());
+ handler.startRemoved();
+ i = onlyOld.iterator();
+ while (i.hasNext()) {
+ String s = (String) i.next();
+ ClassInfo ci = (ClassInfo) oldClassInfo.get(s);
+ if (criteria.validClass(ci))
+ handler.classRemoved(ci);
+ }
+ handler.endRemoved();
+ handler.startAdded();
+ i = onlyNew.iterator();
+ while (i.hasNext()) {
+ String s = (String) i.next();
+ ClassInfo ci = (ClassInfo) newClassInfo.get(s);
+ if (criteria.validClass(ci))
+ handler.classAdded(ci);
+ }
+ handler.endAdded();
+ java.util.Set removedMethods = new TreeSet();
+ java.util.Set removedFields = new TreeSet();
+ java.util.Set addedMethods = new TreeSet();
+ java.util.Set addedFields = new TreeSet();
+ java.util.Set changedMethods = new TreeSet();
+ java.util.Set changedFields = new TreeSet();
+ handler.startChanged();
+ i = both.iterator();
+ while (i.hasNext()) {
+ String s = (String) i.next();
+ ClassInfo oci = (ClassInfo) oldClassInfo.get(s);
+ ClassInfo nci = (ClassInfo) 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();
+ Iterator j = oldMethods.entrySet().iterator();
+ while (j.hasNext()) {
+ Map.Entry entry = (Map.Entry) j.next();
+ if (criteria.validMethod((MethodInfo) entry.getValue()))
+ removedMethods.add(entry.getKey());
+ }
+ j = oldFields.entrySet().iterator();
+ while (j.hasNext()) {
+ Map.Entry entry = (Map.Entry) j.next();
+ if (criteria.validField((FieldInfo) entry.getValue()))
+ removedFields.add(entry.getKey());
+ }
+ j = newMethods.entrySet().iterator();
+ while (j.hasNext()) {
+ Map.Entry entry = (Map.Entry) j.next();
+ if (criteria.validMethod((MethodInfo) entry.getValue()))
+ addedMethods.add(entry.getKey());
+ }
+ j = newFields.entrySet().iterator();
+ while (j.hasNext()) {
+ Map.Entry entry = (Map.Entry) j.next();
+ if (criteria.validField((FieldInfo) entry.getValue()))
+ addedFields.add(entry.getKey());
+ }
+ changedMethods.addAll(removedMethods);
+ changedMethods.retainAll(addedMethods);
+ removedMethods.removeAll(changedMethods);
+ addedMethods.removeAll(changedMethods);
+ changedFields.addAll(removedFields);
+ changedFields.retainAll(addedFields);
+ removedFields.removeAll(changedFields);
+ addedFields.removeAll(changedFields);
+ j = changedMethods.iterator();
+ while (j.hasNext()) {
+ String desc = (String) j.next();
+ MethodInfo oldInfo = (MethodInfo) oldMethods.get(desc);
+ MethodInfo newInfo = (MethodInfo) newMethods.get(desc);
+ if (!criteria.differs(oldInfo, newInfo))
+ j.remove();
+ }
+ j = changedFields.iterator();
+ while (j.hasNext()) {
+ String desc = (String) j.next();
+ FieldInfo oldInfo = (FieldInfo) oldFields.get(desc);
+ FieldInfo newInfo = (FieldInfo) newFields.get(desc);
+ if (!criteria.differs(oldInfo, newInfo))
+ j.remove();
+ }
+ boolean classchanged = criteria.differs(oci, nci);
+ if (classchanged || !removedMethods.isEmpty()
+ || !removedFields.isEmpty() || !addedMethods.isEmpty()
+ || !addedFields.isEmpty() || !changedMethods.isEmpty()
+ || !changedFields.isEmpty()) {
+ handler.startClassChanged(s);
+ handler.startRemoved();
+ j = removedFields.iterator();
+ while (j.hasNext())
+ handler
+ .fieldRemoved((FieldInfo) oldFields.get(j.next()));
+ j = removedMethods.iterator();
+ while (j.hasNext())
+ handler.methodRemoved((MethodInfo)
+ oldMethods.get(j.next()));
+ handler.endRemoved();
+ handler.startAdded();
+ j = addedFields.iterator();
+ while (j.hasNext())
+ handler
+ .fieldAdded((FieldInfo) newFields.get(j.next()));
+ j = addedMethods.iterator();
+ while (j.hasNext())
+ handler.methodAdded((MethodInfo)
+ newMethods.get(j.next()));
+ handler.endAdded();
+ handler.startChanged();
+ if (classchanged)
+ handler.classChanged(oci, nci);
+ j = changedFields.iterator();
+ while (j.hasNext()) {
+ Object tmp = j.next();
+ handler.fieldChanged((FieldInfo) oldFields.get(tmp),
+ (FieldInfo) newFields.get(tmp));
+ }
+ j = changedMethods.iterator();
+ while (j.hasNext()) {
+ Object tmp = j.next();
+ handler.methodChanged((MethodInfo) oldMethods.get(tmp),
+ ((MethodInfo)
+ newMethods.get(tmp)));
+ }
+ handler.endChanged();
+ handler.endClassChanged();
+ removedMethods.clear();
+ removedFields.clear();
+ addedMethods.clear();
+ addedFields.clear();
+ changedMethods.clear();
+ changedFields.clear();
+ }
+ }
+ }
+ handler.endChanged();
+ handler.endDiff();
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/MethodInfo.java b/api/src/main/java/org/osjava/jardiff/MethodInfo.java
new file mode 100644
index 0000000..b83edaa
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/MethodInfo.java
@@ -0,0 +1,105 @@
+/*
+ * org.osjava.jardiff.MethodInfo
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * A class to hold information about a method.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public final class MethodInfo extends AbstractInfo
+{
+ /**
+ * The method descriptor.
+ */
+ private String desc;
+
+ /**
+ * The signature of the method.
+ */
+ private String signature;
+
+ /**
+ * An array of the exceptions thrown by this method.
+ */
+ private String[] exceptions;
+
+ /**
+ * Create a new MethodInfo with the specified parameters.
+ *
+ * @param access The access flags for the method.
+ * @param name The name of the method.
+ * @param signature The signature of the method.
+ * @param exceptions The exceptions thrown by the method.
+ */
+ public MethodInfo(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ super(access, name);
+ this.desc = desc;
+ this.signature = signature;
+ this.exceptions = exceptions;
+ }
+
+ /**
+ * Get the descriptor for the method.
+ *
+ * @return the descriptor
+ */
+ public final String getDesc() {
+ return desc;
+ }
+
+ /**
+ * Get the signature for the method.
+ *
+ * @return the signature
+ */
+ public final String getSignature() {
+ return signature;
+ }
+
+ /**
+ * Get the array of exceptions which can be thrown by the method.
+ *
+ * @return the exceptions as a String[] of internal names.
+ */
+ public final String[] getExceptions() {
+ return exceptions;
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java
new file mode 100644
index 0000000..244b59c
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java
@@ -0,0 +1,159 @@
+/*
+ * org.osjava.jardiff.SimpleDiffCriteria
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * A specific type of DiffCriteria which is only true for classes, methods
+ * and fields which are not synthetic, and are public or protected.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class SimpleDiffCriteria implements DiffCriteria
+{
+ /**
+ * Check if a class is valid.
+ * If the class is not synthetic and is public or protected, return true.
+ *
+ * @param info Info describing the class.
+ * @return True if the class meets the criteria, false otherwise.
+ */
+ public boolean validClass(ClassInfo info) {
+ return !info.isSynthetic() && (info.isPublic() || info.isProtected());
+ }
+
+ /**
+ * Check if a method is valid.
+ * If the method is not synthetic and is public or protected, return true.
+ *
+ * @param info Info describing the method.
+ * @return True if the method meets the criteria, false otherwise.
+ */
+ public boolean validMethod(MethodInfo info) {
+ return !info.isSynthetic() && (info.isPublic() || info.isProtected());
+ }
+
+ /**
+ * Check if a field is valid.
+ * If the method is not synthetic and is public or protected, return true.
+ *
+ * @param info Info describing the field.
+ * @return True if the field meets the criteria, false otherwise.
+ */
+ public boolean validField(FieldInfo info) {
+ return !info.isSynthetic() && (info.isPublic() || info.isProtected());
+ }
+
+ /**
+ * Check if there is a change between two versions of a class.
+ * Returns true if the access flags differ, or if the superclass differs
+ * or if the implemented interfaces differ.
+ *
+ * @param oldInfo Info about the old version of the class.
+ * @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) {
+ if (oldInfo.getAccess() != newInfo.getAccess())
+ return true;
+ // Yes classes can have a null supername, e.g. java.lang.Object !
+ if(oldInfo.getSupername() == null) {
+ if(newInfo.getSupername() != null) {
+ return true;
+ }
+ } else if (!oldInfo.getSupername().equals(newInfo.getSupername())) {
+ return true;
+ }
+ java.util.Set oldInterfaces
+ = new HashSet(Arrays.asList(oldInfo.getInterfaces()));
+ java.util.Set newInterfaces
+ = new HashSet(Arrays.asList(newInfo.getInterfaces()));
+ if (!oldInterfaces.equals(newInterfaces))
+ return true;
+ return false;
+ }
+
+ /**
+ * Check if there is a change between two versions of a method.
+ * Returns true if the access flags differ, or if the thrown
+ * exceptions differ.
+ *
+ * @param oldInfo Info about the old version of the method.
+ * @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 (oldInfo.getAccess() != newInfo.getAccess())
+ return true;
+ if (oldInfo.getExceptions() == null
+ || newInfo.getExceptions() == null) {
+ if (oldInfo.getExceptions() != newInfo.getExceptions())
+ return true;
+ } else {
+ java.util.Set oldExceptions
+ = new HashSet(Arrays.asList(oldInfo.getExceptions()));
+ java.util.Set newExceptions
+ = new HashSet(Arrays.asList(newInfo.getExceptions()));
+ if (!oldExceptions.equals(newExceptions))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if there is a change between two versions of a field.
+ * Returns true if the access flags differ, or if the inital value
+ * of the field differs.
+ *
+ * @param oldInfo Info about the old version of the field.
+ * @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 (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()))
+ 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
new file mode 100644
index 0000000..35847c8
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/StreamDiffHandler.java
@@ -0,0 +1,784 @@
+/*
+ * org.osjava.jardiff.StreamDiffHandler
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/jardiff/src/ava/org/osjava/jardiff/DOMDiffHandler.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import org.objectweb.asm.Type;
+
+/**
+ * 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.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public class StreamDiffHandler implements DiffHandler
+{
+ /**
+ * The XML namespace used.
+ */
+ public static final String XML_URI = "http://www.osjava.org/jardiff/0.1";
+
+ /**
+ * The javax.xml.transform.sax.Transformer used to convert
+ * the DOM to text.
+ */
+ private final BufferedWriter out;
+
+ /**
+ * Create a new StreamDiffHandler which writes to System.out
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public StreamDiffHandler() throws DiffException {
+ try {
+ out = new BufferedWriter(
+ new OutputStreamWriter(System.out, "UTF-8")
+ );
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Create a new StreamDiffHandler with the specified OutputStream.
+ *
+ * @param out Where to write output.
+ */
+ public StreamDiffHandler(OutputStream out)
+ throws DiffException
+ {
+ try {
+ this.out = new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")
+ );
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the diff.
+ * This writes out the start of a &lt;diff&gt; node.
+ *
+ * @param oldJar name of old jar file.
+ * @param newJar name of new jar file.
+ * @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 {
+ try {
+ out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ out.write("<diff xmlns=\"");
+ out.write(xmlEscape(XML_URI));
+ out.write("\" old=\"");
+ out.write(xmlEscape(oldJar));
+ out.write("\" new=\"");
+ out.write(xmlEscape(newJar));
+ out.write("\">");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startOldContents() throws DiffException {
+ try {
+ out.write("<oldcontents>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startNewContents() throws DiffException {
+ try {
+ out.write("<newcontents>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Add a contained class.
+ *
+ * @param info information about a class
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void contains(ClassInfo info) throws DiffException {
+ try {
+ out.write("<class name=\"");
+ out.write(xmlEscape(info.getName()));
+ out.write("\"/>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the list of old contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endOldContents() throws DiffException {
+ try {
+ out.write("</oldcontents>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the list of new contents.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endNewContents() throws DiffException {
+ try {
+ out.write("</newcontents>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the removed node.
+ * This writes out a &lt;removed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startRemoved() throws DiffException {
+ try {
+ out.write("<removed>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out class info for a removed class.
+ * This writes out the nodes describing a class
+ *
+ * @param info The info to write out.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classRemoved(ClassInfo info) throws DiffException {
+ try {
+ writeClassInfo(info);
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the removed section.
+ * This closes the &lt;removed&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endRemoved() throws DiffException {
+ try {
+ out.write("</removed>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the added section.
+ * This opens the &lt;added&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startAdded() throws DiffException {
+ try {
+ out.write("<added>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out the class info for an added class.
+ * This writes out the nodes describing an added class.
+ *
+ * @param info The class info describing the added class.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void classAdded(ClassInfo info) throws DiffException {
+ try {
+ writeClassInfo(info);
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the added section.
+ * This closes the &lt;added&gt; tag.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endAdded() throws DiffException {
+ try {
+ out.write("</added>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start the changed section.
+ * This writes out the &lt;changed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startChanged() throws DiffException {
+ try {
+ out.write("<changed>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Start a changed section for an individual class.
+ * This writes out an &lt;classchanged&gt; node with the real class
+ * name as the name attribute.
+ *
+ * @param internalName the internal name of the class that has changed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void startClassChanged(String internalName) throws DiffException
+ {
+ try {
+ out.write("<classchanged name=\"");
+ out.write(xmlEscape(internalName));
+ out.write("\">");
+ } catch (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
+ * removed section.
+ *
+ * @param info Info about the field that's been removed.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void fieldRemoved(FieldInfo info) throws DiffException {
+ try {
+ writeFieldInfo(info);
+ } catch (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
+ * 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 {
+ try {
+ writeMethodInfo(info);
+ } catch (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
+ * 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 {
+ try {
+ writeFieldInfo(info);
+ } catch (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
+ * added section.
+ *
+ * @param info Info about the added method.
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void methodAdded(MethodInfo info) throws DiffException {
+ try {
+ writeMethodInfo(info);
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out info aboout a changed class.
+ * This writes out a &lt;classchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the class
+ * followed by a &lt;to&gt; node with the new information about the
+ * class.
+ *
+ * @param oldInfo Info about the old class.
+ * @param newInfo Info about the new class.
+ * @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
+ {
+ try {
+ out.write("<classchange><from>");
+ writeClassInfo(oldInfo);
+ out.write("</from><to>");
+ writeClassInfo(newInfo);
+ out.write("</to></classchange>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out info aboout a changed field.
+ * This writes out a &lt;fieldchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the field
+ * followed by a &lt;to&gt; 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(FieldInfo oldInfo, FieldInfo newInfo)
+ throws DiffException
+ {
+ try {
+ out.write("<fieldchange><from>");
+ writeFieldInfo(oldInfo);
+ out.write("</from><to>");
+ writeFieldInfo(newInfo);
+ out.write("</to></fieldchange>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out info aboout a changed method.
+ * This writes out a &lt;methodchange&gt; node, followed by a
+ * &lt;from&gt; node, with the old information about the method
+ * followed by a &lt;to&gt; 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 methodChanged(MethodInfo oldInfo, MethodInfo newInfo)
+ throws DiffException
+ {
+ try {
+ out.write("<methodchange><from>");
+ writeMethodInfo(oldInfo);
+ out.write("</from><to>");
+ writeMethodInfo(newInfo);
+ out.write("</to></methodchange>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the changed section for an individual class.
+ * This closes the &lt;classchanged&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endClassChanged() throws DiffException {
+ try {
+ out.write("</classchanged>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the changed section.
+ * This closes the &lt;changed&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endChanged() throws DiffException {
+ try {
+ out.write("</changed>");
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * End the diff.
+ * This closes the &lt;diff&gt; node.
+ *
+ * @throws DiffException when there is an underlying exception, e.g.
+ * writing to a file caused an IOException
+ */
+ public void endDiff() throws DiffException {
+ try {
+ out.write("</diff>");
+ out.newLine();
+ out.close();
+ } catch (IOException ioe) {
+ throw new DiffException(ioe);
+ }
+ }
+
+ /**
+ * Write out information about a class.
+ * This writes out a &lt;class&gt; node, which contains information about
+ * what interfaces are implemented each in a &lt;implements&gt; node.
+ *
+ * @param info Info about the class to write out.
+ * @throws IOException when there is an underlying IOException.
+ */
+ protected void writeClassInfo(ClassInfo info) throws IOException {
+ out.write("<class");
+ addAccessFlags(info);
+ if(info.getName() != null) {
+ out.write(" name=\"");
+ out.write(xmlEscape(info.getName()));
+ out.write("\"");
+ }
+ if(info.getSignature() != null) {
+ out.write(" signature=\"");
+ out.write(xmlEscape(info.getSignature()));
+ out.write("\"");
+ }
+ if(info.getSupername() != null) {
+ out.write(" superclass=\"");
+ out.write(xmlEscape(info.getSupername()));
+ out.write("\">");
+ }
+ String[] interfaces = info.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ out.write("<implements name=\"");
+ out.write(xmlEscape(interfaces[i]));
+ out.write("\"/>");
+ }
+ out.write("</class>");
+ }
+
+ /**
+ * Write out information about a method.
+ * This writes out a &lt;method&gt; node which contains information about
+ * 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 {
+ out.write("<method");
+
+ addAccessFlags(info);
+
+ if (info.getName() != null) {
+ out.write(" name=\"");
+ out.write(xmlEscape(info.getName()));
+ out.write("\"");
+ }
+ if (info.getSignature() != null) {
+ out.write(" signature=\"");
+ out.write(xmlEscape(info.getSignature()));
+ out.write("\"");
+ }
+ out.write(">");
+ if (info.getDesc() != null) {
+ addMethodNodes(info.getDesc());
+ }
+ String[] exceptions = info.getExceptions();
+ if (exceptions != null) {
+ for (int i = 0; i < exceptions.length; i++) {
+ out.write("<exception name=\"");
+ out.write(xmlEscape(exceptions[i]));
+ out.write("\"/>");
+ }
+ }
+ out.write("</method>");
+ }
+
+ /**
+ * Write out information about a field.
+ * This writes out a &lt;field&gt; node with attributes describing the
+ * field.
+ *
+ * @param info Info about the field.
+ * @throws IOException when there is an underlying IOException.
+ */
+ protected void writeFieldInfo(FieldInfo info) throws IOException {
+ out.write("<field");
+
+ addAccessFlags(info);
+
+ if(info.getName() != null) {
+ out.write(" name=\"");
+ out.write(xmlEscape(info.getName()));
+ out.write("\"");
+ }
+ if (info.getSignature() != null) {
+ out.write(" signature=\"");
+ out.write(xmlEscape(info.getSignature()));
+ out.write("\"");
+ }
+ if (info.getValue() != null) {
+ out.write(" value=\"");
+ out.write(xmlEscape(info.getValue().toString()));
+ out.write("\"");
+ }
+ out.write(">");
+ if (info.getDesc() != null) {
+ addTypeNode(info.getDesc());
+ }
+ out.write("</field>");
+ }
+
+ /**
+ * Add attributes describing some access flags.
+ * This adds the attributes to the attr field.
+ *
+ * @param info Info describing the access flags.
+ * @throws IOException when there is an underlying IOException.
+ */
+ protected void addAccessFlags(AbstractInfo info) throws IOException {
+ out.write(" access=\"");
+ // Doesn't need escaping.
+ out.write(info.getAccessType());
+ out.write("\"");
+ if (info.isAbstract())
+ out.write(" abstract=\"yes\"");
+ if (info.isAnnotation())
+ out.write(" annotation=\"yes\"");
+ if (info.isBridge())
+ out.write(" bridge=\"yes\"");
+ if (info.isDeprecated())
+ out.write(" deprecated=\"yes\"");
+ if (info.isEnum())
+ out.write(" enum=\"yes\"");
+ if (info.isFinal())
+ out.write(" final=\"yes\"");
+ if (info.isInterface())
+ out.write(" interface=\"yes\"");
+ if (info.isNative())
+ out.write(" native=\"yes\"");
+ if (info.isStatic())
+ out.write(" static=\"yes\"");
+ if (info.isStrict())
+ out.write(" strict=\"yes\"");
+ if (info.isSuper())
+ out.write(" super=\"yes\"");
+ if (info.isSynchronized())
+ out.write(" synchronized=\"yes\"");
+ if (info.isSynthetic())
+ out.write(" synthetic=\"yes\"");
+ if (info.isTransient())
+ out.write(" transient=\"yes\"");
+ if (info.isVarargs())
+ out.write(" varargs=\"yes\"");
+ if (info.isVolatile())
+ out.write(" volatile=\"yes\"");
+ }
+
+ /**
+ * Add the method nodes for the method descriptor.
+ * This writes out an &lt;arguments&gt; node containing the
+ * argument types for the method, followed by a &lt;return&gt; 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);
+ out.write("<arguments>");
+ for (int i = 0; i < args.length; i++)
+ addTypeNode(args[i]);
+ out.write("</arguments>");
+ out.write("<return>");
+ addTypeNode(ret);
+ out.write("</return>");
+ }
+
+ /**
+ * 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 {
+ addTypeNode(Type.getType(desc));
+ }
+
+ /**
+ * Add a type node for the specified type.
+ * This writes out a &lt;type&gt; node with attributes describing
+ * the type.
+ *
+ * @param type The type to describe.
+ * @throws IOException when there is an underlying IOException.
+ */
+ protected void addTypeNode(Type type) throws IOException {
+ out.write("<type");
+ int i = type.getSort();
+ if (i == Type.ARRAY) {
+ out.write(" array=\"yes\" dimensions=\"");
+ out.write(""+type.getDimensions());
+ out.write("\"");
+ type = type.getElementType();
+ i = type.getSort();
+ }
+ switch (i) {
+ case Type.BOOLEAN:
+ out.write(" primitive=\"yes\" name=\"boolean\"/>");
+ break;
+ case Type.BYTE:
+ out.write(" primitive=\"yes\" name=\"byte\"/>");
+ break;
+ case Type.CHAR:
+ out.write(" primitive=\"yes\" name=\"char\"/>");
+ break;
+ case Type.DOUBLE:
+ out.write(" primitive=\"yes\" name=\"double\"/>");
+ break;
+ case Type.FLOAT:
+ out.write(" primitive=\"yes\" name=\"float\"/>");
+ break;
+ case Type.INT:
+ out.write(" primitive=\"yes\" name=\"int\"/>");
+ break;
+ case Type.LONG:
+ out.write(" primitive=\"yes\" name=\"long\"/>");
+ break;
+ case Type.OBJECT:
+ out.write(" name=\"");
+ out.write(xmlEscape(type.getInternalName()));
+ out.write("\"/>");
+ break;
+ case Type.SHORT:
+ out.write(" primitive=\"yes\" name=\"short\"/>");
+ break;
+ case Type.VOID:
+ out.write(" primitive=\"yes\" name=\"void\"/>");
+ break;
+ }
+ }
+
+ /**
+ * Escape some text into a format suitable for output as xml.
+ *
+ * @param str the text to format
+ * @return the formatted text
+ */
+ private final String xmlEscape(final String str) {
+ StringBuffer ret = new StringBuffer(str.length());
+ for(int i=0;i<str.length();i++) {
+ char ch = str.charAt(i);
+ switch(ch) {
+ case '<':
+ ret.append("&lt;");
+ break;
+ case '&':
+ ret.append("&amp;");
+ break;
+ case '>':
+ ret.append("&gt;");
+ break;
+ default:
+ ret.append(ch);
+ }
+ }
+ return ret.toString();
+ }
+}
diff --git a/api/src/main/java/org/osjava/jardiff/Tools.java b/api/src/main/java/org/osjava/jardiff/Tools.java
new file mode 100644
index 0000000..23b6445
--- /dev/null
+++ b/api/src/main/java/org/osjava/jardiff/Tools.java
@@ -0,0 +1,80 @@
+/*
+ * org.osjava.jardiff.Tools
+ *
+ * $Id: IOThread.java 1952 2005-08-28 18:03:41Z cybertiger $
+ * $URL: https://svn.osjava.org/svn/osjava/trunk/osjava-nio/src/java/org/osjava/nio/IOThread.java $
+ * $Rev: 1952 $
+ * $Date: 2005-08-28 18:03:41 +0000 (Sun, 28 Aug 2005) $
+ * $Author: cybertiger $
+ *
+ * Copyright (c) 2005, Antony Riley
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * + Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * + Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * + Neither the name JarDiff nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.osjava.jardiff;
+
+/**
+ * A set of Tools which do not belong anywhere else in the API at this time.
+ * This is nasty, but for now, useful.
+ *
+ * @author <a href="mailto:[email protected]">Antony Riley</a>
+ */
+public final class Tools
+{
+ /**
+ * Private constructor so this class can't be instantiated.
+ */
+ private Tools() {
+ /* empty */
+ }
+
+ /**
+ * Get the java class name given an internal class name.
+ * This method currently replaces all instances of $ and / with . this
+ * may not be according to the java language spec, and will almost
+ * certainly fail for some inner classes.
+ *
+ * @param internalName The internal name of the class.
+ * @return The java class name.
+ */
+ public static final String getClassName(String internalName) {
+ StringBuffer ret = new StringBuffer(internalName.length());
+ for (int i = 0; i < internalName.length(); i++) {
+ char ch = internalName.charAt(i);
+ switch (ch) {
+ case '$':
+ case '/':
+ ret.append('.');
+ break;
+ default:
+ ret.append(ch);
+ }
+ }
+ return ret.toString();
+ }
+}