]> source.dussan.org Git - aspectj.git/commitdiff
[j9] Basic read/write of Module attribute
authorAndy Clement <aclement@pivotal.io>
Mon, 6 Jun 2016 19:00:12 +0000 (12:00 -0700)
committerAndy Clement <aclement@pivotal.io>
Mon, 6 Jun 2016 19:00:12 +0000 (12:00 -0700)
37 files changed:
bcel-builder/src/org/aspectj/apache/bcel/Constants.java
bcel-builder/src/org/aspectj/apache/bcel/classfile/Module.java [new file with mode: 0644]
bcel-builder/testdata/modules/cpl.sh [new file with mode: 0755]
bcel-builder/testdata/modules/one/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/one/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/a/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/a/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/b/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/b/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/c/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/c/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/d/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/d/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/C1.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/C2.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/C3.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/com/foo1/C1.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/com/foo2/C2.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/com/foo3/C3.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/e/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/f/I1.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/f/com/foo1/I1.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/f/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/f/module-info.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/C1.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/C2.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/I1.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/I2.java [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/com/foo1/C1.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/com/foo1/I1.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/com/foo2/C2.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/com/foo2/I2.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/module-info.class [new file with mode: 0644]
bcel-builder/testdata/modules/two/g/module-info.java [new file with mode: 0644]
bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/BcelTestCase.java
bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ModuleTest.java [new file with mode: 0644]

index 4499284c202f8ea4c458abba03a30fc92132310d..8d8427006287781ff1daf18163649b2f629e0dc6 100644 (file)
@@ -80,6 +80,8 @@ public interface Constants {
        public final static short MINOR_1_7 = 0;
        public final static short MAJOR_1_8 = 52;
        public final static short MINOR_1_8 = 0;
+       public final static short MAJOR_1_9 = 53;
+       public final static short MINOR_1_9 = 0;
        // Defaults
        public final static short MAJOR = MAJOR_1_1;
        public final static short MINOR = MINOR_1_1;
@@ -105,12 +107,18 @@ public interface Constants {
        public final static short ACC_INTERFACE = 0x0200;
        public final static short ACC_ABSTRACT = 0x0400;
        public final static short ACC_STRICT = 0x0800;
-
+       
        public final static short ACC_ANNOTATION = 0x2000;
        public final static short ACC_ENUM = 0x4000;
+       public final static int ACC_MODULE = 0x8000;
        public final static short ACC_BRIDGE = 0x0040;
        public final static short ACC_VARARGS = 0x0080;
 
+       // module related
+       public final static int MODULE_ACC_PUBLIC    = 0x0020;
+       public final static int MODULE_ACC_SYNTHETIC = 0x1000;
+       public final static int MODULE_ACC_MANDATED  = 0x8000;
+       
        // Applies to classes compiled by new compilers only
        public final static short ACC_SUPER = 0x0020;
 
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Module.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Module.java
new file mode 100644 (file)
index 0000000..217f5fb
--- /dev/null
@@ -0,0 +1,432 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache BCEL" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache BCEL", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.aspectj.apache.bcel.classfile;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Module.Export;
+
+/**
+ * This class is derived from <em>Attribute</em> and represents the module
+ * information captured in a class file.
+ * http://cr.openjdk.java.net/~mr/jigsaw/spec/lang-vm.html
+ * 
+ * @author Andy Clement
+ */
+public final class Module extends Attribute {
+
+       private static final String[] NO_MODULE_NAMES = {};
+       
+       private byte[] moduleInfo;
+       private int ptr;
+       private boolean unpacked = false;
+       private Require[] requires;
+       private Export[] exports;
+       private Uses[] uses;
+       private Provide[] provides;
+
+       /**
+        * Build a Module attribute from a previously Unknown attribute.
+        */
+       public Module(Unknown unknown) {
+               super(unknown.getTag(), unknown.getNameIndex(), unknown.getLength(), unknown.getConstantPool());
+               moduleInfo = unknown.getBytes();
+       }
+
+       public class Require {
+
+               private final int moduleNameIndex;
+               private final int requiresFlags;
+
+               public Require(int moduleNameIndex, int requiresFlags) {
+                       this.moduleNameIndex = moduleNameIndex;
+                       this.requiresFlags = requiresFlags;
+               }
+               
+               public String getModuleName() {
+                       return cpool.getConstantUtf8(moduleNameIndex).getStringValue();
+               }
+               
+               public int getRequiresFlags() {
+                       return requiresFlags;
+               }
+
+               public String getRequiresFlagsAsString() {
+                       StringBuilder s = new StringBuilder();
+                       if ((requiresFlags & Constants.MODULE_ACC_PUBLIC)!=0) {
+                               s.append("public ");
+                       }
+                       if ((requiresFlags & Constants.MODULE_ACC_SYNTHETIC)!=0) {
+                               s.append("synthetic ");
+                       }
+                       if ((requiresFlags & Constants.MODULE_ACC_MANDATED)!=0) {
+                               s.append("mandated ");
+                       }
+                       return s.toString();
+               }
+               
+               public String toString() {
+                       return "requires "+getRequiresFlagsAsString()+getModuleName();
+               }
+               
+       }
+
+       
+       public class Export {
+
+               private final int exportedPackageNameIndex;
+               private final int[] toModuleNameIndices;
+
+               public Export(int exportedPackageNameIndex, int[] toModuleNameIndices) {
+                       this.exportedPackageNameIndex = exportedPackageNameIndex;
+                       this.toModuleNameIndices = toModuleNameIndices;
+               }
+
+               public String getExportedPackage() {
+                       return cpool.getConstantUtf8(exportedPackageNameIndex).getStringValue();
+               }
+
+               public String[] getToModuleNames() {
+                       if (toModuleNameIndices==null) {
+                               return NO_MODULE_NAMES;
+                       }
+                       String[] toModuleNames = new String[toModuleNameIndices.length];
+                       for (int i=0;i<toModuleNameIndices.length;i++) {
+                               toModuleNames[i] = cpool.getConstantUtf8(toModuleNameIndices[i]).getStringValue();
+                       }
+                       return toModuleNames;
+               }
+               
+               public String toString() {
+                       StringBuilder s =new StringBuilder();
+                       s.append("exports ").append(getExportedPackage().replace('/', '.'));
+                       String[] toModules = getToModuleNames();
+                       if (toModules.length!=0) {
+                               s.append(" to ");
+                               for (int i=0;i<toModules.length;i++) {
+                                       if (i>0) {
+                                               s.append(", ");
+                                       }
+                                       s.append(toModules[i]);
+                               }
+                       }
+                       return s.toString().trim();
+               }
+       }
+
+       public class Provide {
+               private final int providedTypeIndex;
+               private final int withTypeIndex;
+
+               public Provide(int providedTypeIndex, int withTypeIndex) {
+                       this.providedTypeIndex = providedTypeIndex;
+                       this.withTypeIndex = withTypeIndex;
+               }
+               
+               public String getProvidedType() {
+                       return cpool.getConstantString_CONSTANTClass(providedTypeIndex);
+               }
+               
+               public int getProvidedTypeIndex() {
+                       return providedTypeIndex;
+               }
+
+               public String getWithType() {
+                       return  cpool.getConstantString_CONSTANTClass(withTypeIndex);
+               }
+
+               public int getWithTypeIndex() {
+                       return withTypeIndex;
+               }
+
+               public String toString() {
+                       StringBuilder s =new StringBuilder();
+                       s.append("provides ").append(getProvidedType().replace('/', '.'));
+                       s.append(" with ").append(getWithType().replace('/','.'));
+                       return s.toString();
+               }
+       }
+
+       public class Uses {
+               private final int typeNameIndex;
+               
+               public Uses(int typeNameIndex) {
+                       this.typeNameIndex = typeNameIndex;
+               }
+
+               public String getTypeName() {
+                       return  cpool.getConstantString_CONSTANTClass(typeNameIndex);
+               }
+
+               public int getTypeNameIndex() {
+                       return typeNameIndex;
+               }
+               
+               public String toString() {
+                       StringBuilder s =new StringBuilder();
+                       s.append("uses ").append(getTypeName().replace('/', '.'));
+                       return s.toString().trim();
+               }
+       }
+       
+       private final int readInt() {
+               return ((moduleInfo[ptr++] & 0xFF) << 24) + ((moduleInfo[ptr++] & 0xFF) << 16)
+                               + ((moduleInfo[ptr++] & 0xFF) << 8) + (moduleInfo[ptr++] & 0xFF);
+       }
+
+       private final int readUnsignedShort() {
+               return ((moduleInfo[ptr++] & 0xff) << 8) + (moduleInfo[ptr++] & 0xff);
+       }
+
+       private final int readUnsignedShort(int offset) {
+               return ((moduleInfo[offset++] & 0xff) << 8) + (moduleInfo[offset] & 0xff);
+       }
+
+       private void ensureUnpacked() {
+               if (!unpacked) {
+                       ptr = 0;
+                       int count = readUnsignedShort();
+                       requires = new Require[count];
+                       for (int i = 0; i < count; i++) {
+                               requires[i] = new Require(readUnsignedShort(), readUnsignedShort());
+                       }
+                       count = readUnsignedShort();
+                       exports = new Export[count];
+                       for (int i = 0; i < count; i++) {
+                               int index = readUnsignedShort();
+                               int toCount = readUnsignedShort();
+                               int[] to = new int[toCount];
+                               for (int j = 0; j < toCount; j++) {
+                                       to[j] = readUnsignedShort();
+                               }
+                               exports[i] = new Export(index, to);
+                       }
+                       count = readUnsignedShort();
+                       uses = new Uses[count];
+                       for (int i = 0; i < count; i++) {
+                               uses[i] = new Uses(readUnsignedShort());
+                       }
+                       count = readUnsignedShort();
+                       provides = new Provide[count];
+                       for (int i = 0; i < count; i++) {
+                               provides[i] = new Provide(readUnsignedShort(), readUnsignedShort());
+                       }
+                       unpacked = true;
+               }
+       }
+
+       @Override
+       public final void dump(DataOutputStream file) throws IOException {
+               super.dump(file);
+               if (!unpacked) {
+                       file.write(moduleInfo);
+               } else {
+                       file.writeShort(requires.length);
+                       for (int i = 0; i < requires.length; i++) {
+                               file.writeShort(requires[i].moduleNameIndex);
+                               file.writeShort(requires[i].requiresFlags);
+                       }
+                       file.writeShort(exports.length);
+                       for (Export export : exports) {
+                               file.writeShort(export.exportedPackageNameIndex);
+                               int[] toIndices = export.toModuleNameIndices;
+                               file.writeShort(toIndices.length);
+                               for (int index : toIndices) {
+                                       file.writeShort(index);
+                               }
+                       }
+                       file.writeShort(uses.length);
+                       for (Uses use : uses) {
+                               file.writeShort(use.getTypeNameIndex());
+                       }
+                       file.writeShort(provides.length);
+                       for (Provide provide : provides) {
+                               file.writeShort(provide.providedTypeIndex);
+                               file.writeShort(provide.withTypeIndex);
+                       }
+               }
+       }
+
+       public String toStringRequires() {
+               StringBuilder s = new StringBuilder();
+               s.append('#').append(requires.length);
+               if (requires.length > 0) {
+                       for (Require require : requires) {
+                               s.append(' ');
+                               s.append(require.moduleNameIndex).append(':').append(require.requiresFlags);
+                       }
+               }
+               return s.toString();
+       }
+
+       public String toStringExports() {
+               StringBuilder s = new StringBuilder();
+               s.append('#').append(exports.length);
+               if (exports.length > 0) {
+                       for (Export export : exports) {
+                               s.append(' ');
+                               s.append(export.exportedPackageNameIndex).append(":[");
+                               int[] toIndices = export.toModuleNameIndices;
+                               for (int i = 0; i < toIndices.length; i++) {
+                                       if (i > 0)
+                                               s.append(',');
+                                       s.append(toIndices[i]);
+                               }
+                               s.append("]");
+                       }
+               }
+               return s.toString();
+       }
+
+       public String toStringUses() {
+               StringBuilder s = new StringBuilder();
+               s.append('#').append(uses.length);
+               if (uses.length > 0) {
+                       for (Uses use : uses) {
+                               s.append(' ');
+                               s.append(use.getTypeName());
+                       }
+               }
+               return s.toString();
+       }
+
+       public String toStringProvides() {
+               StringBuilder s = new StringBuilder();
+               s.append('#').append(provides.length);
+               if (provides.length > 0) {
+                       for (Provide provide : provides) {
+                               s.append(' ');
+                               s.append(provide.providedTypeIndex).append(':').append(provide.withTypeIndex);
+                       }
+               }
+               return s.toString();
+       }
+
+       @Override
+       public final String toString() {
+               StringBuilder s = new StringBuilder();
+               ensureUnpacked();
+               s.append("Module(");
+               if (requires.length != 0) {
+                       s.append("requires=");
+                       s.append(toStringRequires());
+                       s.append(" ");
+               }
+               if (exports.length != 0) {
+                       s.append("exports=");
+                       s.append(toStringExports());
+                       s.append(" ");
+               }
+               if (uses.length != 0) {
+                       s.append("uses=");
+                       s.append(toStringUses());
+                       s.append(" ");
+               }
+               if (provides.length != 0) {
+                       s.append("provides=");
+                       s.append(toStringProvides());
+                       s.append(" ");
+               }
+               return s.toString().trim()+")";
+       }
+
+       /**
+        * @return deep copy of this attribute //
+        */
+       // @Override
+       // public Attribute copy(ConstantPool constant_pool) {
+       // return (SourceFile) clone();
+       // }
+       @Override
+       public void accept(ClassVisitor v) {
+               v.visitSourceFile(this);
+       }
+       
+       public Require[] getRequires() {
+               ensureUnpacked();
+               return requires;
+       }
+
+       public String[] getRequiredModuleNames() {
+               ensureUnpacked();
+               String[] results = new String[requires.length];
+               for (int i=0;i<requires.length;i++) {
+                       results[i] = cpool.getConstantUtf8(requires[i].moduleNameIndex).getStringValue();
+               }
+               return results;
+       }
+       
+       public byte[] getBytes() {
+               return moduleInfo;
+       }
+
+       public Export[] getExports() {
+               ensureUnpacked();
+               return exports;
+       }
+
+       public Uses[] getUses() {
+               ensureUnpacked();
+               return uses;
+       }
+
+       public Provide[] getProvides() {
+               ensureUnpacked();
+               return provides;
+       }
+}
diff --git a/bcel-builder/testdata/modules/cpl.sh b/bcel-builder/testdata/modules/cpl.sh
new file mode 100755 (executable)
index 0000000..0ac2145
--- /dev/null
@@ -0,0 +1,24 @@
+cd one
+javac module-info.java
+cd ..
+cd two/a
+javac module-info.java
+cd ../..
+cd two/b
+javac module-info.java
+cd ../..
+cd two/c
+javac module-info.java
+cd ../..
+cd two/d
+javac module-info.java -modulepath ../a:../b
+cd ../..
+cd two/e
+javac module-info.java C1.java C2.java C3.java -d . -modulepath ../a:../b
+cd ../..
+cd two/f
+javac module-info.java I1.java -d . 
+cd ../..
+cd two/g
+javac module-info.java I1.java I2.java C1.java C2.java -d . 
+cd ../..
diff --git a/bcel-builder/testdata/modules/one/module-info.class b/bcel-builder/testdata/modules/one/module-info.class
new file mode 100644 (file)
index 0000000..0088bd1
Binary files /dev/null and b/bcel-builder/testdata/modules/one/module-info.class differ
diff --git a/bcel-builder/testdata/modules/one/module-info.java b/bcel-builder/testdata/modules/one/module-info.java
new file mode 100644 (file)
index 0000000..d0913de
--- /dev/null
@@ -0,0 +1 @@
+module one {}
diff --git a/bcel-builder/testdata/modules/two/a/module-info.class b/bcel-builder/testdata/modules/two/a/module-info.class
new file mode 100644 (file)
index 0000000..c0003b8
Binary files /dev/null and b/bcel-builder/testdata/modules/two/a/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/a/module-info.java b/bcel-builder/testdata/modules/two/a/module-info.java
new file mode 100644 (file)
index 0000000..8ab4a7d
--- /dev/null
@@ -0,0 +1,2 @@
+module a.b.c {
+}
diff --git a/bcel-builder/testdata/modules/two/b/module-info.class b/bcel-builder/testdata/modules/two/b/module-info.class
new file mode 100644 (file)
index 0000000..6721be1
Binary files /dev/null and b/bcel-builder/testdata/modules/two/b/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/b/module-info.java b/bcel-builder/testdata/modules/two/b/module-info.java
new file mode 100644 (file)
index 0000000..308ba05
--- /dev/null
@@ -0,0 +1,2 @@
+module b.c.d {
+}
diff --git a/bcel-builder/testdata/modules/two/c/module-info.class b/bcel-builder/testdata/modules/two/c/module-info.class
new file mode 100644 (file)
index 0000000..0c81601
Binary files /dev/null and b/bcel-builder/testdata/modules/two/c/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/c/module-info.java b/bcel-builder/testdata/modules/two/c/module-info.java
new file mode 100644 (file)
index 0000000..501d75a
--- /dev/null
@@ -0,0 +1,2 @@
+module c.d.e {
+}
diff --git a/bcel-builder/testdata/modules/two/d/module-info.class b/bcel-builder/testdata/modules/two/d/module-info.class
new file mode 100644 (file)
index 0000000..3586246
Binary files /dev/null and b/bcel-builder/testdata/modules/two/d/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/d/module-info.java b/bcel-builder/testdata/modules/two/d/module-info.java
new file mode 100644 (file)
index 0000000..5b9446e
--- /dev/null
@@ -0,0 +1,4 @@
+module d.e.f {
+  requires a.b.c;
+  requires public b.c.d;
+}
diff --git a/bcel-builder/testdata/modules/two/e/C1.java b/bcel-builder/testdata/modules/two/e/C1.java
new file mode 100644 (file)
index 0000000..eb08784
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo1;
+
+public class C1 {}
diff --git a/bcel-builder/testdata/modules/two/e/C2.java b/bcel-builder/testdata/modules/two/e/C2.java
new file mode 100644 (file)
index 0000000..528b87e
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo2;
+
+public class C2 {}
diff --git a/bcel-builder/testdata/modules/two/e/C3.java b/bcel-builder/testdata/modules/two/e/C3.java
new file mode 100644 (file)
index 0000000..205f75f
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo3;
+
+public class C3 {}
diff --git a/bcel-builder/testdata/modules/two/e/com/foo1/C1.class b/bcel-builder/testdata/modules/two/e/com/foo1/C1.class
new file mode 100644 (file)
index 0000000..6b5bb5f
Binary files /dev/null and b/bcel-builder/testdata/modules/two/e/com/foo1/C1.class differ
diff --git a/bcel-builder/testdata/modules/two/e/com/foo2/C2.class b/bcel-builder/testdata/modules/two/e/com/foo2/C2.class
new file mode 100644 (file)
index 0000000..d9eec8b
Binary files /dev/null and b/bcel-builder/testdata/modules/two/e/com/foo2/C2.class differ
diff --git a/bcel-builder/testdata/modules/two/e/com/foo3/C3.class b/bcel-builder/testdata/modules/two/e/com/foo3/C3.class
new file mode 100644 (file)
index 0000000..d64d2fc
Binary files /dev/null and b/bcel-builder/testdata/modules/two/e/com/foo3/C3.class differ
diff --git a/bcel-builder/testdata/modules/two/e/module-info.class b/bcel-builder/testdata/modules/two/e/module-info.class
new file mode 100644 (file)
index 0000000..565bbbe
Binary files /dev/null and b/bcel-builder/testdata/modules/two/e/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/e/module-info.java b/bcel-builder/testdata/modules/two/e/module-info.java
new file mode 100644 (file)
index 0000000..2300970
--- /dev/null
@@ -0,0 +1,5 @@
+module e.f.g {
+  exports com.foo1;
+  exports com.foo2 to a.b.c;
+  exports com.foo3 to a.b.c, b.c.d;
+}
diff --git a/bcel-builder/testdata/modules/two/f/I1.java b/bcel-builder/testdata/modules/two/f/I1.java
new file mode 100644 (file)
index 0000000..88029d8
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo1;
+
+public interface I1 {}
diff --git a/bcel-builder/testdata/modules/two/f/com/foo1/I1.class b/bcel-builder/testdata/modules/two/f/com/foo1/I1.class
new file mode 100644 (file)
index 0000000..da13682
Binary files /dev/null and b/bcel-builder/testdata/modules/two/f/com/foo1/I1.class differ
diff --git a/bcel-builder/testdata/modules/two/f/module-info.class b/bcel-builder/testdata/modules/two/f/module-info.class
new file mode 100644 (file)
index 0000000..9377bb8
Binary files /dev/null and b/bcel-builder/testdata/modules/two/f/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/f/module-info.java b/bcel-builder/testdata/modules/two/f/module-info.java
new file mode 100644 (file)
index 0000000..7897862
--- /dev/null
@@ -0,0 +1,3 @@
+module f.g.h {
+  uses com.foo1.I1;
+}
diff --git a/bcel-builder/testdata/modules/two/g/C1.java b/bcel-builder/testdata/modules/two/g/C1.java
new file mode 100644 (file)
index 0000000..e25a57e
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo1;
+
+public class C1 implements I1 {}
diff --git a/bcel-builder/testdata/modules/two/g/C2.java b/bcel-builder/testdata/modules/two/g/C2.java
new file mode 100644 (file)
index 0000000..100c37b
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo2;
+
+public class C2 implements I2 {}
diff --git a/bcel-builder/testdata/modules/two/g/I1.java b/bcel-builder/testdata/modules/two/g/I1.java
new file mode 100644 (file)
index 0000000..88029d8
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo1;
+
+public interface I1 {}
diff --git a/bcel-builder/testdata/modules/two/g/I2.java b/bcel-builder/testdata/modules/two/g/I2.java
new file mode 100644 (file)
index 0000000..bd52da8
--- /dev/null
@@ -0,0 +1,3 @@
+package com.foo2;
+
+public interface I2 {}
diff --git a/bcel-builder/testdata/modules/two/g/com/foo1/C1.class b/bcel-builder/testdata/modules/two/g/com/foo1/C1.class
new file mode 100644 (file)
index 0000000..dfc9448
Binary files /dev/null and b/bcel-builder/testdata/modules/two/g/com/foo1/C1.class differ
diff --git a/bcel-builder/testdata/modules/two/g/com/foo1/I1.class b/bcel-builder/testdata/modules/two/g/com/foo1/I1.class
new file mode 100644 (file)
index 0000000..da13682
Binary files /dev/null and b/bcel-builder/testdata/modules/two/g/com/foo1/I1.class differ
diff --git a/bcel-builder/testdata/modules/two/g/com/foo2/C2.class b/bcel-builder/testdata/modules/two/g/com/foo2/C2.class
new file mode 100644 (file)
index 0000000..aae7ea2
Binary files /dev/null and b/bcel-builder/testdata/modules/two/g/com/foo2/C2.class differ
diff --git a/bcel-builder/testdata/modules/two/g/com/foo2/I2.class b/bcel-builder/testdata/modules/two/g/com/foo2/I2.class
new file mode 100644 (file)
index 0000000..c31533f
Binary files /dev/null and b/bcel-builder/testdata/modules/two/g/com/foo2/I2.class differ
diff --git a/bcel-builder/testdata/modules/two/g/module-info.class b/bcel-builder/testdata/modules/two/g/module-info.class
new file mode 100644 (file)
index 0000000..415a540
Binary files /dev/null and b/bcel-builder/testdata/modules/two/g/module-info.class differ
diff --git a/bcel-builder/testdata/modules/two/g/module-info.java b/bcel-builder/testdata/modules/two/g/module-info.java
new file mode 100644 (file)
index 0000000..00633c5
--- /dev/null
@@ -0,0 +1,4 @@
+module g.h.i {
+  provides com.foo1.I1 with com.foo1.C1;
+  provides com.foo2.I2 with com.foo2.C2;
+}
index 3311c538675afdeebbf57acf26e4aa1dffdc4499..ef4b8a9a739493dab6359bdb5c675f6f2341d8d7 100644 (file)
@@ -1,5 +1,5 @@
 /* *******************************************************************
- * Copyright (c) 2004, 2013 IBM, VMware
+ * Copyright (c) 2004 - 2016 IBM, VMware, Contributors
  * All rights reserved. 
  * This program and the accompanying materials are made available 
  * under the terms of the Eclipse Public License v1.0 
@@ -34,8 +34,7 @@ import org.aspectj.apache.bcel.util.SyntheticRepository;
 /**
  * Super class for the Java5 tests, includes various helper methods.
  */
-
-public class BcelTestCase extends TestCase {
+public abstract class BcelTestCase extends TestCase {
 
        private boolean verbose = false;
 
@@ -175,4 +174,13 @@ public class BcelTestCase extends TestCase {
                return null;
        }
 
+       public Attribute getAttribute(Attribute[] attrs, String name) {
+               for (Attribute attr: attrs) {
+                       if (attr.getName().equals(name)) {
+                               return attr;
+                       }
+               }
+               return null;
+       }
+
 }
diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ModuleTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ModuleTest.java
new file mode 100644 (file)
index 0000000..d6e2b45
--- /dev/null
@@ -0,0 +1,129 @@
+/* *******************************************************************
+ * Copyright (c) 2016 Contributors
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Eclipse Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement -     initial implementation 
+ * ******************************************************************/
+
+package org.aspectj.apache.bcel.classfile.tests;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Attribute;
+import org.aspectj.apache.bcel.classfile.ClassParser;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.Module;
+import org.aspectj.apache.bcel.classfile.Module.Export;
+import org.aspectj.apache.bcel.classfile.Module.Provide;
+import org.aspectj.apache.bcel.classfile.Module.Require;
+import org.aspectj.apache.bcel.classfile.Module.Uses;
+import org.aspectj.apache.bcel.classfile.SourceFile;
+import org.aspectj.apache.bcel.classfile.Unknown;
+
+/**
+ * http://cr.openjdk.java.net/~mr/jigsaw/spec/lang-vm.html
+ * 
+ * @author Andy Clement
+ */
+public class ModuleTest extends BcelTestCase {
+
+       public void testLoadSimpleModuleClass() throws Exception {
+               String moduleFilename = "testdata/modules/one/module-info.class";
+               ClassParser classParser = new ClassParser(moduleFilename);
+               JavaClass javaClass = classParser.parse();
+               assertNotNull(javaClass);
+               assertEquals(Constants.MAJOR_1_9,javaClass.getMajor());
+               assertEquals(Constants.MINOR_1_9,javaClass.getMinor());
+               assertEquals(Constants.ACC_MODULE,javaClass.getModifiers()); 
+               assertEquals(0,javaClass.getSuperclassNameIndex());
+               assertEquals(0,javaClass.getInterfaceIndices().length);
+               assertEquals(0,javaClass.getFields().length);
+               assertEquals(0,javaClass.getMethods().length);
+               Attribute[] attrs = javaClass.getAttributes();
+               assertEquals(2,attrs.length);
+               SourceFile sourceFile = (SourceFile) getAttribute(attrs,Constants.ATTR_SOURCE_FILE);
+               Module moduleAttr = new Module((Unknown)getAttribute(attrs,Constants.ATTR_UNKNOWN));
+               byte[] originalData = moduleAttr.getBytes();
+               String[] requiredModuleNames = moduleAttr.getRequiredModuleNames();
+               assertEquals(1,requiredModuleNames.length);
+               assertEquals("java.base",requiredModuleNames[0]);
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               moduleAttr.dump(new DataOutputStream(baos));
+               byte[] newData = baos.toByteArray();
+               // The 6 offset here is because the newdata includes the 2byte cpool pointer for the name 'Module'
+               // and the 4byte int length field for the attribute data
+               if (newData.length!=originalData.length+6) {
+                       fail("Expected the length of the original attribute ("+originalData.length+") to match the new written length ("+newData.length+")");
+               }
+               for (int i=0;i<originalData.length;i++) {
+                       if (originalData[i]!=newData[i+6]) {
+                               fail("byte mismatch at position "+i+" of "+newData.length);
+                       }
+               }
+       }
+       
+
+       public void testRequires() throws Exception {
+               Module moduleAttr = getModuleAttribute("testdata/modules/two/d/module-info.class");
+               Require[] requires = moduleAttr.getRequires();
+               assertEquals(3,requires.length);
+               assertEquals("requires mandated java.base",requires[0].toString());
+               assertEquals("requires a.b.c",requires[1].toString());
+               assertEquals("requires public b.c.d",requires[2].toString());
+               assertEquals("java.base",requires[0].getModuleName());
+               assertEquals("a.b.c",requires[1].getModuleName());
+               assertEquals("b.c.d",requires[2].getModuleName());
+       }
+       
+       public void testExports() throws Exception {
+               Module moduleAttr = getModuleAttribute("testdata/modules/two/e/module-info.class");
+               Export[] exports = moduleAttr.getExports();
+               assertEquals(3,exports.length);
+               assertEquals("exports com.foo1",exports[0].toString());
+               assertEquals("exports com.foo2 to a.b.c",exports[1].toString());
+               assertEquals("exports com.foo3 to b.c.d, a.b.c",exports[2].toString());
+               assertEquals("com/foo1",exports[0].getExportedPackage());
+               assertEquals("com/foo2",exports[1].getExportedPackage());
+               assertEquals("com/foo3",exports[2].getExportedPackage());
+               assertEquals("a.b.c",exports[1].getToModuleNames()[0]);
+               assertEquals("b.c.d",exports[2].getToModuleNames()[0]);
+               assertEquals("a.b.c",exports[2].getToModuleNames()[1]);
+       }
+       
+       public void testUses() throws Exception {
+               Module moduleAttr = getModuleAttribute("testdata/modules/two/f/module-info.class");
+               Uses[] uses = moduleAttr.getUses();
+               assertEquals(1,uses.length);
+               assertEquals("com/foo1/I1",uses[0].getTypeName());
+               assertEquals("uses com.foo1.I1",uses[0].toString());
+       }
+       
+       public void testProvides() throws Exception {
+               Module moduleAttr = getModuleAttribute("testdata/modules/two/g/module-info.class");
+               Provide[] provides = moduleAttr.getProvides();
+               assertEquals(2,provides.length);
+               assertEquals("provides com.foo1.I1 with com.foo1.C1",provides[0].toString());
+               assertEquals("provides com.foo2.I2 with com.foo2.C2",provides[1].toString());
+               assertEquals("com/foo1/I1",provides[0].getProvidedType());
+               assertEquals("com/foo1/C1",provides[0].getWithType());
+               assertEquals("com/foo2/I2",provides[1].getProvidedType());
+               assertEquals("com/foo2/C2",provides[1].getWithType());
+       }
+
+       // ---
+       
+       private Module getModuleAttribute(String moduleInfoClass) throws Exception {
+               ClassParser classParser = new ClassParser(moduleInfoClass);
+               JavaClass javaClass = classParser.parse();
+               Module moduleAttr = new Module((Unknown)getAttribute(javaClass.getAttributes(),Constants.ATTR_UNKNOWN));
+               return moduleAttr;
+       }
+       
+}