You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/08/27 21:57:24 UTC

[commons-bcel] branch master updated: Add missing Java 9 and Java 11 class file attributes. (#33)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-bcel.git


The following commit(s) were added to refs/heads/master by this push:
     new 8dc6bba  Add missing Java 9 and Java 11 class file attributes. (#33)
8dc6bba is described below

commit 8dc6bbae4dff5434ae0a112f1a9ace6066074906
Author: Mark Roberts <ma...@users.noreply.github.com>
AuthorDate: Tue Aug 27 14:57:20 2019 -0700

    Add missing Java 9 and Java 11 class file attributes. (#33)
    
    * Add missing Java 9 and Java 11 class file attributes.
    
    * update for newer attributes
    
    * add missing visitor needed by java 11
    
    * Correct version number comments.
    Supply default visitMethodParameter implementation for Visitor interface.
---
 src/examples/ClassDumper.java                      |  25 +-
 src/main/java/org/apache/bcel/Const.java           |  91 +++++---
 .../java/org/apache/bcel/classfile/Attribute.java  |  10 +
 .../org/apache/bcel/classfile/BootstrapMethod.java |   6 +-
 .../apache/bcel/classfile/BootstrapMethods.java    |  11 +-
 .../org/apache/bcel/classfile/ConstantPackage.java |   2 +-
 .../org/apache/bcel/classfile/ConstantPool.java    |  18 +-
 .../apache/bcel/classfile/DescendingVisitor.java   | 105 +++++++++
 .../org/apache/bcel/classfile/EmptyVisitor.java    |  54 ++++-
 .../java/org/apache/bcel/classfile/InnerClass.java |   4 +-
 .../org/apache/bcel/classfile/InnerClasses.java    |   2 +-
 .../java/org/apache/bcel/classfile/JavaClass.java  |   2 +-
 .../org/apache/bcel/classfile/MethodParameter.java |   4 +
 .../java/org/apache/bcel/classfile/Module.java     | 257 +++++++++++++++++++++
 .../org/apache/bcel/classfile/ModuleExports.java   | 125 ++++++++++
 .../org/apache/bcel/classfile/ModuleMainClass.java | 137 +++++++++++
 .../org/apache/bcel/classfile/ModuleOpens.java     | 125 ++++++++++
 .../org/apache/bcel/classfile/ModulePackages.java  | 175 ++++++++++++++
 .../org/apache/bcel/classfile/ModuleProvides.java  | 121 ++++++++++
 .../org/apache/bcel/classfile/ModuleRequires.java  | 114 +++++++++
 .../java/org/apache/bcel/classfile/NestHost.java   | 138 +++++++++++
 .../org/apache/bcel/classfile/NestMembers.java     | 176 ++++++++++++++
 .../java/org/apache/bcel/classfile/Visitor.java    |  52 +++++
 .../org/apache/bcel/generic/ConstantPoolGen.java   |   4 +
 .../verifier/statics/StringRepresentation.java     |   9 +
 .../org/apache/bcel/visitors/CounterVisitor.java   | 101 ++++++++
 26 files changed, 1816 insertions(+), 52 deletions(-)

diff --git a/src/examples/ClassDumper.java b/src/examples/ClassDumper.java
index bc2ed20..7fe2752 100644
--- a/src/examples/ClassDumper.java
+++ b/src/examples/ClassDumper.java
@@ -162,8 +162,8 @@ class ClassDumper {
 
             // All eight byte constants take up two spots in the constant pool
             tag = constant_items[i].getTag();
-            if ((tag == Constants.CONSTANT_Double) ||
-                    (tag == Constants.CONSTANT_Long)) {
+            if ((tag == Const.CONSTANT_Double) ||
+                    (tag == Const.CONSTANT_Long)) {
                 i++;
             }
         }
@@ -179,11 +179,11 @@ class ClassDumper {
         /* Interfaces are implicitely abstract, the flag should be set
          * according to the JVM specification.
          */
-        if ((access_flags & Constants.ACC_INTERFACE) != 0) {
-            access_flags |= Constants.ACC_ABSTRACT;
+        if ((access_flags & Const.ACC_INTERFACE) != 0) {
+            access_flags |= Const.ACC_ABSTRACT;
         }
-        if (((access_flags & Constants.ACC_ABSTRACT) != 0)
-                && ((access_flags & Constants.ACC_FINAL) != 0)) {
+        if (((access_flags & Const.ACC_ABSTRACT) != 0)
+                && ((access_flags & Const.ACC_FINAL) != 0)) {
             throw new ClassFormatException("Class " + file_name +
                     " can't be both final and abstract");
         }
@@ -197,7 +197,10 @@ class ClassDumper {
 
         superclass_name_index = file.readUnsignedShort();
         System.out.printf("  super_class: %d (", superclass_name_index); 
-        System.out.println(constantToString(superclass_name_index) + ")"); 
+        if (superclass_name_index > 0) {
+            System.out.printf("%s", constantToString(superclass_name_index));
+        }
+        System.out.println(")");
     }
 
     /**
@@ -224,7 +227,7 @@ class ClassDumper {
             }
             System.out.println(interfaces[i] + " (" +
                     constant_pool.getConstantString(interfaces[i],
-                            Constants.CONSTANT_Class) + ")"); 
+                            Const.CONSTANT_Class) + ")");
         }
     }
 
@@ -283,7 +286,11 @@ class ClassDumper {
 
         for (int i = 0; i < attributes_count; i++) {
             attributes[i] = Attribute.readAttribute(file, constant_pool);
-            System.out.printf("  %s%n", attributes[i]); 
+            // indent all lines by two spaces
+            String[] lines = attributes[i].toString().split("\\r?\\n");
+            for (String line : lines) {
+                System.out.println("  " + line);
+            }
         }
     }
 
diff --git a/src/main/java/org/apache/bcel/Const.java b/src/main/java/org/apache/bcel/Const.java
index 722daba..79268ae 100644
--- a/src/main/java/org/apache/bcel/Const.java
+++ b/src/main/java/org/apache/bcel/Const.java
@@ -208,12 +208,14 @@ public final class Const {
   public static final int MAX_BYTE  = 255; // 2^8 - 1
 
   /** One of the access flags for fields, methods, or classes.
-   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5'>
-   *  Flag definitions for Fields in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
-   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6'>
-   *  Flag definitions for Methods in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
-   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6-300-D.1-D.1'>
-   *  Flag definitions for Classes in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
+   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1'>
+   *  Flag definitions for Classes in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5'>
+   *  Flag definitions for Fields in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6'>
+   *  Flag definitions for Methods in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+   *  @see <a href='http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.6-300-D.1-D.1'>
+   *  Flag definitions for Inner Classes in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
    */
   public static final short ACC_PUBLIC       = 0x0001;
 
@@ -237,89 +239,110 @@ public final class Const {
    */
   public static final short ACC_FINAL        = 0x0010;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for the Module attribute.
+   *  @see #ACC_PUBLIC
+   */
+  public static final short ACC_OPEN         = 0x0020;
+
+  /** One of the access flags for classes.
+   *  @see #ACC_PUBLIC
+   */
+  public static final short ACC_SUPER        = 0x0020;
+
+  /** One of the access flags for methods.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_SYNCHRONIZED = 0x0020;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for the Module attribute.
    *  @see #ACC_PUBLIC
    */
-  public static final short ACC_VOLATILE     = 0x0040;
+  public static final short ACC_TRANSITIVE   = 0x0020;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for methods.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_BRIDGE       = 0x0040;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for the Module attribute.
+   *  @see #ACC_PUBLIC
+   */
+  public static final short ACC_STATIC_PHASE = 0x0040;
+
+  /** One of the access flags for fields.
+   *  @see #ACC_PUBLIC
+   */
+  public static final short ACC_VOLATILE     = 0x0040;
+
+  /** One of the access flags for fields.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_TRANSIENT    = 0x0080;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for methods.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_VARARGS      = 0x0080;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for methods.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_NATIVE       = 0x0100;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for classes.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_INTERFACE    = 0x0200;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for methods or classes.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_ABSTRACT     = 0x0400;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for methods.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_STRICT       = 0x0800;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for fields, methods, classes, MethodParameter attribute, or Module attribute.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_SYNTHETIC    = 0x1000;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for classes.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_ANNOTATION   = 0x2000;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for fields or classes.
    *  @see #ACC_PUBLIC
    */
   public static final short ACC_ENUM         = 0x4000;
 
-  /** One of the access flags for fields, methods, or classes.
-   *  @see #ACC_PUBLIC
-   */
-  public static final short ACC_MANDATED     = (short) 0x8000;
-
   // Applies to classes compiled by new compilers only
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for MethodParameter or Module attributes.
    *  @see #ACC_PUBLIC
    */
-  public static final short ACC_SUPER        = 0x0020;
+  public static final short ACC_MANDATED     = (short) 0x8000;
 
-  /** One of the access flags for fields, methods, or classes.
+  /** One of the access flags for classes.
    *  @see #ACC_PUBLIC
    */
-  public static final short MAX_ACC_FLAG     = ACC_ENUM;
+  public static final short ACC_MODULE       = (short) 0x8000;
+  public static final int MAX_ACC_FLAG       = 0x8000; // ACC_MODULE is negative as a short
 
+  // Note that do to overloading:
+  // 'synchronized' is for methods, might be 'open' (if Module), 'super' (if class), or 'transitive' (if Module).
+  // 'volatile'     is for fields,  might be 'bridge' (if method) or 'static_phase' (if Module)
+  // 'transient'    is for fields,  might be 'varargs' (if method)
+  // 'module'       is for classes, might be 'mandated' (if Module or MethodParameters)
   /**
    * The names of the access flags.
    */
   private static final String[] ACCESS_NAMES = {
     "public", "private", "protected", "static", "final", "synchronized",
     "volatile", "transient", "native", "interface", "abstract", "strictfp",
-    "synthetic", "annotation", "enum"
+    "synthetic", "annotation", "enum", "module"
   };
 
   /** @since 6.0 */
@@ -2288,8 +2311,13 @@ public final class Const {
   public static final byte ATTR_STACK_MAP_TABLE                         = 19;
   public static final byte ATTR_BOOTSTRAP_METHODS                       = 20;
   public static final byte ATTR_METHOD_PARAMETERS                       = 21;
+  public static final byte ATTR_MODULE                                  = 22;
+  public static final byte ATTR_MODULE_PACKAGES                         = 23;
+  public static final byte ATTR_MODULE_MAIN_CLASS                       = 24;
+  public static final byte ATTR_NEST_HOST                               = 25;
+  public static final byte ATTR_NEST_MEMBERS                            = 26;
 
-  public static final short KNOWN_ATTRIBUTES = 22; // count of attributes
+  public static final short KNOWN_ATTRIBUTES = 27; // count of attributes
 
   private static final String[] ATTRIBUTE_NAMES = {
     "SourceFile", "ConstantValue", "Code", "Exceptions",
@@ -2299,7 +2327,8 @@ public final class Const {
     "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations",
     "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations",
     "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", "StackMapTable",
-    "BootstrapMethods", "MethodParameters"
+    "BootstrapMethods", "MethodParameters", "Module", "ModulePackages",
+    "ModuleMainClass", "NestHost", "NestMembers"
   };
 
   /**
diff --git a/src/main/java/org/apache/bcel/classfile/Attribute.java b/src/main/java/org/apache/bcel/classfile/Attribute.java
index cc4d93b..e833c96 100644
--- a/src/main/java/org/apache/bcel/classfile/Attribute.java
+++ b/src/main/java/org/apache/bcel/classfile/Attribute.java
@@ -182,6 +182,16 @@ public abstract class Attribute implements Cloneable, Node {
                 return new BootstrapMethods(name_index, length, file, constant_pool);
             case Const.ATTR_METHOD_PARAMETERS:
                 return new MethodParameters(name_index, length, file, constant_pool);
+            case Const.ATTR_MODULE:
+                return new Module(name_index, length, file, constant_pool);
+            case Const.ATTR_MODULE_PACKAGES:
+                return new ModulePackages(name_index, length, file, constant_pool);
+            case Const.ATTR_MODULE_MAIN_CLASS:
+                return new ModuleMainClass(name_index, length, file, constant_pool);
+            case Const.ATTR_NEST_HOST:
+                return new NestHost(name_index, length, file, constant_pool);
+            case Const.ATTR_NEST_MEMBERS:
+                return new NestMembers(name_index, length, file, constant_pool);
             default:
                 // Never reached
                 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
diff --git a/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java b/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
index a742aea..f5e7de3 100644
--- a/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
+++ b/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
@@ -129,12 +129,12 @@ public class BootstrapMethod implements Cloneable {
         String bootstrap_method_name;
         bootstrap_method_name = constant_pool.constantToString(bootstrap_method_ref,
                 Const.CONSTANT_MethodHandle);
-        buf.append(Utility.compactClassName(bootstrap_method_name));
+        buf.append(Utility.compactClassName(bootstrap_method_name, false));
         final int num_bootstrap_arguments = bootstrap_arguments.length;
         if (num_bootstrap_arguments > 0) {
-            buf.append("\n     Method Arguments:");
+            buf.append("\nMethod Arguments:");
             for (int i = 0; i < num_bootstrap_arguments; i++) {
-                buf.append("\n     ").append(i).append(": ");
+                buf.append("\n  ").append(i).append(": ");
                 buf.append(constant_pool.constantToString(constant_pool.getConstant(bootstrap_arguments[i])));
             }
         }
diff --git a/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java b/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
index acc17fb..9418e2d 100644
--- a/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
+++ b/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
@@ -134,10 +134,17 @@ public class BootstrapMethods extends Attribute {
         final StringBuilder buf = new StringBuilder();
         buf.append("BootstrapMethods(");
         buf.append(bootstrap_methods.length);
-        buf.append("):\n");
+        buf.append("):");
         for (int i = 0; i < bootstrap_methods.length; i++) {
+            buf.append("\n");
+            final int start = buf.length();
             buf.append("  ").append(i).append(": ");
-            buf.append(bootstrap_methods[i].toString(super.getConstantPool())).append("\n");
+            final int indent_count = buf.length() - start;
+            final String[] lines = (bootstrap_methods[i].toString(super.getConstantPool())).split("\\r?\\n");
+            buf.append(lines[0]);
+            for (int j = 1; j < lines.length; j++) {
+                buf.append("\n").append("          ".substring(0,indent_count)).append(lines[j]);
+            }
         }
         return buf.toString();
     }
diff --git a/src/main/java/org/apache/bcel/classfile/ConstantPackage.java b/src/main/java/org/apache/bcel/classfile/ConstantPackage.java
index ed43284..ee01317 100644
--- a/src/main/java/org/apache/bcel/classfile/ConstantPackage.java
+++ b/src/main/java/org/apache/bcel/classfile/ConstantPackage.java
@@ -67,7 +67,7 @@ public final class ConstantPackage extends Constant implements ConstantObject {
 
 
     /**
-     * Called by objects that are traversing the nodes of the tree implicitely
+     * Called by objects that are traversing the nodes of the tree implicitly
      * defined by the contents of a Java class. I.e., the hierarchy of methods,
      * fields, attributes, etc. spawns a tree of objects.
      *
diff --git a/src/main/java/org/apache/bcel/classfile/ConstantPool.java b/src/main/java/org/apache/bcel/classfile/ConstantPool.java
index f7fdecf..f2c946a 100644
--- a/src/main/java/org/apache/bcel/classfile/ConstantPool.java
+++ b/src/main/java/org/apache/bcel/classfile/ConstantPool.java
@@ -154,6 +154,16 @@ public class ConstantPool implements Cloneable, Node {
                         + ":" + constantToString(cid.getNameAndTypeIndex(),
                         Const.CONSTANT_NameAndType);
                 break;
+            case Const.CONSTANT_Module:
+                i = ((ConstantModule) c).getNameIndex();
+                c = getConstant(i, Const.CONSTANT_Utf8);
+                str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
+                break;
+            case Const.CONSTANT_Package:
+                i = ((ConstantPackage) c).getNameIndex();
+                c = getConstant(i, Const.CONSTANT_Utf8);
+                str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
+                break;
             default: // Never reached
                 throw new RuntimeException("Unknown constant type " + tag);
         }
@@ -279,7 +289,7 @@ public class ConstantPool implements Cloneable, Node {
         Constant c;
         int i;
         c = getConstant(index, tag);
-        /* This switch() is not that elegant, since the two classes have the
+        /* This switch() is not that elegant, since the four classes have the
          * same contents, they just differ in the name of the index
          * field variable.
          * But we want to stick to the JVM naming conventions closely though
@@ -293,6 +303,12 @@ public class ConstantPool implements Cloneable, Node {
             case Const.CONSTANT_String:
                 i = ((ConstantString) c).getStringIndex();
                 break;
+            case Const.CONSTANT_Module:
+                i = ((ConstantModule) c).getNameIndex();
+                break;
+            case Const.CONSTANT_Package:
+                i = ((ConstantPackage) c).getNameIndex();
+                break;
             default:
                 throw new RuntimeException("getConstantString called with illegal tag " + tag);
         }
diff --git a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
index fa89526..b2d9883 100644
--- a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
+++ b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
@@ -500,6 +500,21 @@ public class DescendingVisitor implements Visitor
     {
         stack.push(obj);
         obj.accept(visitor);
+        final MethodParameter[] table = obj.getParameters();
+        for (final MethodParameter element : table) {
+            element.accept(this);
+        }
+        stack.pop();
+    }
+
+    /**
+     * @since 6.4
+     */
+    @Override
+    public void visitMethodParameter(final MethodParameter obj)
+    {
+        stack.push(obj);
+        obj.accept(visitor);
         stack.pop();
     }
 
@@ -550,4 +565,94 @@ public class DescendingVisitor implements Visitor
         obj.accept(visitor);
         stack.pop();
     }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModule(final Module obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        final ModuleRequires[] rtable = obj.getRequiresTable();
+        for (final ModuleRequires element : rtable) {
+            element.accept(this);
+        }
+        final ModuleExports[] etable = obj.getExportsTable();
+        for (final ModuleExports element : etable) {
+            element.accept(this);
+        }
+        stack.pop();
+        final ModuleOpens[] otable = obj.getOpensTable();
+        for (final ModuleOpens element : otable) {
+            element.accept(this);
+        }
+        stack.pop();
+        final ModuleProvides[] ptable = obj.getProvidesTable();
+        for (final ModuleProvides element : ptable) {
+            element.accept(this);
+        }
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleRequires(final ModuleRequires obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleExports(final ModuleExports obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleOpens(final ModuleOpens obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleProvides(final ModuleProvides obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModulePackages(final ModulePackages obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleMainClass(final ModuleMainClass obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestHost(final NestHost obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestMembers(final NestMembers obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        stack.pop();
+    }
 }
diff --git a/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java b/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
index 795e0ce..e60606f 100644
--- a/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
+++ b/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
@@ -275,6 +275,14 @@ public class EmptyVisitor implements Visitor
     }
 
     /**
+     * @since 6.4
+     */
+    @Override
+    public void visitMethodParameter(final MethodParameter obj)
+    {
+    }
+
+    /**
      * @since 6.0
      */
     @Override
@@ -310,11 +318,55 @@ public class EmptyVisitor implements Visitor
     public void visitConstantModule(final ConstantModule constantModule) {
     }
 
-
     /**
      * @since 6.3
      */
     @Override
     public void visitConstantDynamic(final ConstantDynamic obj) {
     }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModule(final Module obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleRequires(final ModuleRequires obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleExports(final ModuleExports obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleOpens(final ModuleOpens obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleProvides(final ModuleProvides obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModulePackages(final ModulePackages obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleMainClass(final ModuleMainClass obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestHost(final NestHost obj) {
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestMembers(final NestMembers obj) {
+    }
 }
diff --git a/src/main/java/org/apache/bcel/classfile/InnerClass.java b/src/main/java/org/apache/bcel/classfile/InnerClass.java
index 287e481..94d2c88 100644
--- a/src/main/java/org/apache/bcel/classfile/InnerClass.java
+++ b/src/main/java/org/apache/bcel/classfile/InnerClass.java
@@ -182,11 +182,11 @@ public final class InnerClass implements Cloneable, Node {
         String inner_name;
         String inner_class_name = constant_pool.getConstantString(inner_class_index,
                 Const.CONSTANT_Class);
-        inner_class_name = Utility.compactClassName(inner_class_name);
+        inner_class_name = Utility.compactClassName(inner_class_name, false);
         if (outer_class_index != 0) {
             outer_class_name = constant_pool.getConstantString(outer_class_index,
                     Const.CONSTANT_Class);
-            outer_class_name = " of class " + Utility.compactClassName(outer_class_name);
+            outer_class_name = " of class " + Utility.compactClassName(outer_class_name, false);
         } else {
             outer_class_name = "";
         }
diff --git a/src/main/java/org/apache/bcel/classfile/InnerClasses.java b/src/main/java/org/apache/bcel/classfile/InnerClasses.java
index 30f4f11..565294f 100644
--- a/src/main/java/org/apache/bcel/classfile/InnerClasses.java
+++ b/src/main/java/org/apache/bcel/classfile/InnerClasses.java
@@ -135,7 +135,7 @@ public final class InnerClasses extends Attribute {
         for (final InnerClass inner_class : inner_classes) {
             buf.append(inner_class.toString(super.getConstantPool())).append("\n");
         }
-        return buf.toString();
+        return buf.substring(0, buf.length()-1); // remove the last newline
     }
 
 
diff --git a/src/main/java/org/apache/bcel/classfile/JavaClass.java b/src/main/java/org/apache/bcel/classfile/JavaClass.java
index bcafc05..b2ed8d7 100644
--- a/src/main/java/org/apache/bcel/classfile/JavaClass.java
+++ b/src/main/java/org/apache/bcel/classfile/JavaClass.java
@@ -721,7 +721,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
                       boolean innerClassAttributeRefersToMe = false;
                       String inner_class_name = constant_pool.getConstantString(innerClasse.getInnerClassIndex(),
                                  Const.CONSTANT_Class);
-                      inner_class_name = Utility.compactClassName(inner_class_name);
+                      inner_class_name = Utility.compactClassName(inner_class_name, false);
                       if (inner_class_name.equals(getClassName())) {
                           innerClassAttributeRefersToMe = true;
                       }
diff --git a/src/main/java/org/apache/bcel/classfile/MethodParameter.java b/src/main/java/org/apache/bcel/classfile/MethodParameter.java
index e881af5..a0345b9 100644
--- a/src/main/java/org/apache/bcel/classfile/MethodParameter.java
+++ b/src/main/java/org/apache/bcel/classfile/MethodParameter.java
@@ -91,6 +91,10 @@ public class MethodParameter implements Cloneable {
         return (access_flags & Const.ACC_MANDATED) != 0;
     }
 
+    public void accept(final Visitor v) {
+        v.visitMethodParameter(this);
+    }
+
     /**
      * Dump object to file stream on binary format.
      *
diff --git a/src/main/java/org/apache/bcel/classfile/Module.java b/src/main/java/org/apache/bcel/classfile/Module.java
new file mode 100644
index 0000000..28673a1
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/Module.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or provided by a module.
+ * There may be at most one Module attribute in a ClassFile structure.
+ *
+ * @see   Attribute
+ * @since 6.4
+ */
+public final class Module extends Attribute {
+
+    private int module_name_index;
+    private int module_flags;
+    private int module_version_index;
+
+    private ModuleRequires[] requires_table;
+    private ModuleExports[] exports_table;
+    private ModuleOpens[] opens_table;
+    private int uses_count;
+    private int uses_index[];
+    private ModuleProvides[] provides_table;
+
+    /**
+     * Construct object from input stream.
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param input Input stream
+     * @param constant_pool Array of constants
+     * @throws IOException
+     */
+    Module(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
+        super(Const.ATTR_MODULE, name_index, length, constant_pool);
+
+        module_name_index = input.readUnsignedShort();
+        module_flags = input.readUnsignedShort();
+        module_version_index = input.readUnsignedShort();
+
+        final int requires_count = input.readUnsignedShort();
+        requires_table = new ModuleRequires[requires_count];
+        for (int i = 0; i < requires_count; i++) {
+            requires_table[i] = new ModuleRequires(input);
+        }
+
+        final int exports_count = input.readUnsignedShort();
+        exports_table = new ModuleExports[exports_count];
+        for (int i = 0; i < exports_count; i++) {
+            exports_table[i] = new ModuleExports(input);
+        }
+
+        final int opens_count = input.readUnsignedShort();
+        opens_table = new ModuleOpens[opens_count];
+        for (int i = 0; i < opens_count; i++) {
+            opens_table[i] = new ModuleOpens(input);
+        }
+
+        uses_count = input.readUnsignedShort();
+        uses_index = new int[uses_count];
+        for (int i = 0; i < uses_count; i++) {
+            uses_index[i] = input.readUnsignedShort();
+        }
+
+        final int provides_count = input.readUnsignedShort();
+        provides_table = new ModuleProvides[provides_count];
+        for (int i = 0; i < provides_count; i++) {
+            provides_table[i] = new ModuleProvides(input);
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModule(this);
+    }
+
+    // TODO add more getters and setters?
+
+    /**
+     * @return table of required modules
+     * @see ModuleRequires
+     */
+    public final ModuleRequires[] getRequiresTable() {
+        return requires_table;
+    }
+
+
+    /**
+     * @return table of exported interfaces
+     * @see ModuleExports
+     */
+    public final ModuleExports[] getExportsTable() {
+        return exports_table;
+    }
+
+
+    /**
+     * @return table of provided interfaces
+     * @see ModuleOpens
+     */
+    public final ModuleOpens[] getOpensTable() {
+        return opens_table;
+    }
+
+
+    /**
+     * @return table of provided interfaces
+     * @see ModuleProvides
+     */
+    public final ModuleProvides[] getProvidesTable() {
+        return provides_table;
+    }
+
+
+    /**
+     * Dump Module attribute to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException
+     */
+    @Override
+    public final void dump( final DataOutputStream file ) throws IOException {
+        super.dump(file);
+
+        file.writeShort(module_name_index);
+        file.writeShort(module_flags);
+        file.writeShort(module_version_index);
+
+        file.writeShort(requires_table.length);
+        for (final ModuleRequires entry : requires_table) {
+            entry.dump(file);
+        }
+
+        file.writeShort(exports_table.length);
+        for (final ModuleExports entry : exports_table) {
+            entry.dump(file);
+        }
+
+        file.writeShort(opens_table.length);
+        for (final ModuleOpens entry : opens_table) {
+            entry.dump(file);
+        }
+
+        file.writeShort(uses_index.length);
+        for (final int entry : uses_index) {
+            file.writeShort(entry);
+        }
+
+        file.writeShort(provides_table.length);
+        for (final ModuleProvides entry : provides_table) {
+            entry.dump(file);
+        }
+    }
+
+
+    /**
+     * @return String representation, i.e., a list of packages.
+     */
+    @Override
+    public final String toString() {
+        final ConstantPool cp = super.getConstantPool();
+        final StringBuilder buf = new StringBuilder();
+        buf.append("Module:\n");
+        buf.append("  name:    ") .append(cp.getConstantString(module_name_index, Const.CONSTANT_Module).replace('/', '.')).append("\n");
+        buf.append("  flags:   ") .append(String.format("%04x", module_flags)).append("\n");
+        final String version = (module_version_index == 0 ? "0" : cp.getConstantString(module_version_index, Const.CONSTANT_Utf8));
+        buf.append("  version: ") .append(version).append("\n");
+
+        buf.append("  requires(").append(requires_table.length).append("):\n");
+        for (final ModuleRequires module : requires_table) {
+            buf.append("    ").append(module.toString(cp)).append("\n");
+        }
+
+        buf.append("  exports(").append(exports_table.length).append("):\n");
+        for (final ModuleExports module : exports_table) {
+            buf.append("    ").append(module.toString(cp)).append("\n");
+        }
+
+        buf.append("  opens(").append(opens_table.length).append("):\n");
+        for (final ModuleOpens module : opens_table) {
+            buf.append("    ").append(module.toString(cp)).append("\n");
+        }
+
+        buf.append("  uses(").append(uses_index.length).append("):\n");
+        for (final int index : uses_index) {
+            final String class_name = cp.getConstantString(index, Const.CONSTANT_Class);
+            buf.append("    ").append(Utility.compactClassName(class_name, false)).append("\n");
+        }
+
+        buf.append("  provides(").append(provides_table.length).append("):\n");
+        for (final ModuleProvides module : provides_table) {
+            buf.append("    ").append(module.toString(cp)).append("\n");
+        }
+
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this attribute
+     */
+    @Override
+    public Attribute copy( final ConstantPool _constant_pool ) {
+        final Module c = (Module) clone();
+
+        c.requires_table = new ModuleRequires[requires_table.length];
+        for (int i = 0; i < requires_table.length; i++) {
+            c.requires_table[i] = requires_table[i].copy();
+        }
+
+        c.exports_table = new ModuleExports[exports_table.length];
+        for (int i = 0; i < exports_table.length; i++) {
+            c.exports_table[i] = exports_table[i].copy();
+        }
+
+        c.opens_table = new ModuleOpens[opens_table.length];
+        for (int i = 0; i < opens_table.length; i++) {
+            c.opens_table[i] = opens_table[i].copy();
+        }
+
+        c.provides_table = new ModuleProvides[provides_table.length];
+        for (int i = 0; i < provides_table.length; i++) {
+            c.provides_table[i] = provides_table[i].copy();
+        }
+
+        c.setConstantPool(_constant_pool);
+        return c;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModuleExports.java b/src/main/java/org/apache/bcel/classfile/ModuleExports.java
new file mode 100644
index 0000000..2b7a984
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModuleExports.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class represents an entry in the exports table of the Module attribute.
+ * Each entry describes a package which may open the parent module.
+ *
+ * @see   Module
+ * @since 6.4
+ */
+public final class ModuleExports implements Cloneable, Node {
+
+    private int exports_index;  // points to CONSTANT_Package_info
+    private int exports_flags;
+    private int exports_to_count;
+    private int exports_to_index[];  // points to CONSTANT_Module_info
+
+
+    /**
+     * Construct object from file stream.
+     *
+     * @param file Input stream
+     * @throws IOException if an I/O Exception occurs in readUnsignedShort
+     */
+    ModuleExports(final DataInput file) throws IOException {
+        exports_index = file.readUnsignedShort();
+        exports_flags = file.readUnsignedShort();
+        exports_to_count = file.readUnsignedShort();
+        exports_to_index = new int[exports_to_count];
+        for (int i = 0; i < exports_to_count; i++) {
+            exports_to_index[i] = file.readUnsignedShort();
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModuleExports(this);
+    }
+
+    // TODO add more getters and setters?
+
+    /**
+     * Dump table entry to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException if an I/O Exception occurs in writeShort
+     */
+    public final void dump( final DataOutputStream file ) throws IOException {
+        file.writeShort(exports_index);
+        file.writeShort(exports_flags);
+        file.writeShort(exports_to_count);
+        for (final int entry : exports_to_index) {
+            file.writeShort(entry);
+        }
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return "exports(" + exports_index + ", " + exports_flags + ", " + exports_to_count + ", ...)";
+    }
+
+
+    /**
+     * @return Resolved string representation
+     */
+    public final String toString( final ConstantPool constant_pool ) {
+        final StringBuilder buf = new StringBuilder();
+        final String package_name = constant_pool.constantToString(exports_index, Const.CONSTANT_Package);
+        buf.append(Utility.compactClassName(package_name, false));
+        buf.append(", ").append(String.format("%04x", exports_flags));
+        buf.append(", to(").append(exports_to_count).append("):\n");
+        for (final int index : exports_to_index) {
+            final String module_name = constant_pool.getConstantString(index, Const.CONSTANT_Module);
+            buf.append("      ").append(Utility.compactClassName(module_name, false)).append("\n");
+        }
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this object
+     */
+    public ModuleExports copy() {
+        try {
+            return (ModuleExports) clone();
+        } catch (final CloneNotSupportedException e) {
+            // TODO should this throw?
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModuleMainClass.java b/src/main/java/org/apache/bcel/classfile/ModuleMainClass.java
new file mode 100644
index 0000000..f270f05
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModuleMainClass.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class is derived from <em>Attribute</em> and indicates the main class of a module.
+ * There may be at most one ModuleMainClass attribute in a ClassFile structure.
+ *
+ * @see     Attribute
+ */
+public final class ModuleMainClass extends Attribute {
+
+    private int main_class_index;
+
+
+    /**
+     * Initialize from another object. Note that both objects use the same
+     * references (shallow copy). Use copy() for a physical copy.
+     */
+    public ModuleMainClass(final ModuleMainClass c) {
+        this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
+    }
+
+
+    /**
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param int Host class index
+     * @param constant_pool Array of constants
+     */
+    public ModuleMainClass(final int name_index, final int length, final int main_class_index,
+            final ConstantPool constant_pool) {
+        super(Const.ATTR_NEST_MEMBERS, name_index, length, constant_pool);
+        this.main_class_index = main_class_index;
+    }
+
+
+    /**
+     * Construct object from input stream.
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param input Input stream
+     * @param constant_pool Array of constants
+     * @throws IOException
+     */
+    ModuleMainClass(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
+        this(name_index, length, 0, constant_pool);
+        main_class_index = input.readUnsignedShort();
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModuleMainClass(this);
+    }
+
+
+    /**
+     * Dump ModuleMainClass attribute to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException
+     */
+    @Override
+    public final void dump( final DataOutputStream file ) throws IOException {
+        super.dump(file);
+        file.writeShort(main_class_index);
+    }
+
+
+    /**
+     * @return index into constant pool of host class name.
+     */
+    public final int getHostClassIndex() {
+        return main_class_index;
+    }
+
+
+    /**
+     * @param int the host class index
+     */
+    public final void setHostClassIndex( final int main_class_index ) {
+        this.main_class_index = main_class_index;
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("ModuleMainClass: ");
+        final String class_name = super.getConstantPool().getConstantString(main_class_index, Const.CONSTANT_Class);
+        buf.append(Utility.compactClassName(class_name, false));
+        return buf.toString();
+    }
+
+
+    /**
+     * @return deep copy of this attribute
+     */
+    @Override
+    public Attribute copy( final ConstantPool _constant_pool ) {
+        final ModuleMainClass c = (ModuleMainClass) clone();
+        c.setConstantPool(_constant_pool);
+        return c;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModuleOpens.java b/src/main/java/org/apache/bcel/classfile/ModuleOpens.java
new file mode 100644
index 0000000..a197676
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModuleOpens.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class represents an entry in the opens table of the Module attribute.
+ * Each entry describes a package which the parent module opens.
+ *
+ * @see   Module
+ * @since 6.4
+ */
+public final class ModuleOpens implements Cloneable, Node {
+
+    private int opens_index;  // points to CONSTANT_Package_info
+    private int opens_flags;
+    private int opens_to_count;
+    private int opens_to_index[];  // points to CONSTANT_Module_info
+
+
+    /**
+     * Construct object from file stream.
+     *
+     * @param file Input stream
+     * @throws IOException if an I/O Exception occurs in readUnsignedShort
+     */
+    ModuleOpens(final DataInput file) throws IOException {
+        opens_index = file.readUnsignedShort();
+        opens_flags = file.readUnsignedShort();
+        opens_to_count = file.readUnsignedShort();
+        opens_to_index = new int[opens_to_count];
+        for (int i = 0; i < opens_to_count; i++) {
+            opens_to_index[i] = file.readUnsignedShort();
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModuleOpens(this);
+    }
+
+    // TODO add more getters and setters?
+
+    /**
+     * Dump table entry to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException if an I/O Exception occurs in writeShort
+     */
+    public final void dump( final DataOutputStream file ) throws IOException {
+        file.writeShort(opens_index);
+        file.writeShort(opens_flags);
+        file.writeShort(opens_to_count);
+        for (final int entry : opens_to_index) {
+            file.writeShort(entry);
+        }
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return "opens(" + opens_index + ", " + opens_flags + ", " + opens_to_count + ", ...)";
+    }
+
+
+    /**
+     * @return Resolved string representation
+     */
+    public final String toString( final ConstantPool constant_pool ) {
+        final StringBuilder buf = new StringBuilder();
+        final String package_name = constant_pool.constantToString(opens_index, Const.CONSTANT_Package);
+        buf.append(Utility.compactClassName(package_name, false));
+        buf.append(", ").append(String.format("%04x", opens_flags));
+        buf.append(", to(").append(opens_to_count).append("):\n");
+        for (final int index : opens_to_index) {
+            final String module_name = constant_pool.getConstantString(index, Const.CONSTANT_Module);
+            buf.append("      ").append(Utility.compactClassName(module_name, false)).append("\n");
+        }
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this object
+     */
+    public ModuleOpens copy() {
+        try {
+            return (ModuleOpens) clone();
+        } catch (final CloneNotSupportedException e) {
+            // TODO should this throw?
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModulePackages.java b/src/main/java/org/apache/bcel/classfile/ModulePackages.java
new file mode 100644
index 0000000..95df9dc
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModulePackages.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the Module attribute.
+ * There may be at most one ModulePackages attribute in a ClassFile structure.
+ *
+ * @see     Attribute
+ */
+public final class ModulePackages extends Attribute {
+
+    private int[] package_index_table;
+
+
+    /**
+     * Initialize from another object. Note that both objects use the same
+     * references (shallow copy). Use copy() for a physical copy.
+     */
+    public ModulePackages(final ModulePackages c) {
+        this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
+    }
+
+
+    /**
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param package_index_table Table of indices in constant pool
+     * @param constant_pool Array of constants
+     */
+    public ModulePackages(final int name_index, final int length, final int[] package_index_table,
+            final ConstantPool constant_pool) {
+        super(Const.ATTR_MODULE_PACKAGES, name_index, length, constant_pool);
+        this.package_index_table = package_index_table != null ? package_index_table : new int[0];
+    }
+
+
+    /**
+     * Construct object from input stream.
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param input Input stream
+     * @param constant_pool Array of constants
+     * @throws IOException
+     */
+    ModulePackages(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
+        this(name_index, length, (int[]) null, constant_pool);
+        final int number_of_packages = input.readUnsignedShort();
+        package_index_table = new int[number_of_packages];
+        for (int i = 0; i < number_of_packages; i++) {
+            package_index_table[i] = input.readUnsignedShort();
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModulePackages(this);
+    }
+
+
+    /**
+     * Dump ModulePackages attribute to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException
+     */
+    @Override
+    public final void dump( final DataOutputStream file ) throws IOException {
+        super.dump(file);
+        file.writeShort(package_index_table.length);
+        for (final int index : package_index_table) {
+            file.writeShort(index);
+        }
+    }
+
+
+    /**
+     * @return array of indices into constant pool of package names.
+     */
+    public final int[] getPackageIndexTable() {
+        return package_index_table;
+    }
+
+
+    /**
+     * @return Length of package table.
+     */
+    public final int getNumberOfPackages() {
+        return package_index_table == null ? 0 : package_index_table.length;
+    }
+
+
+    /**
+     * @return string array of package names
+     */
+    public final String[] getPackageNames() {
+        final String[] names = new String[package_index_table.length];
+        for (int i = 0; i < package_index_table.length; i++) {
+            names[i] = super.getConstantPool().getConstantString(package_index_table[i],
+                    Const.CONSTANT_Package).replace('/', '.');
+        }
+        return names;
+    }
+
+
+    /**
+     * @param package_index_table the list of package indexes
+     * Also redefines number_of_packages according to table length.
+     */
+    public final void setPackageIndexTable( final int[] package_index_table ) {
+        this.package_index_table = package_index_table != null ? package_index_table : new int[0];
+    }
+
+
+    /**
+     * @return String representation, i.e., a list of packages.
+     */
+    @Override
+    public final String toString() {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("ModulePackages(");
+        buf.append(package_index_table.length);
+        buf.append("):\n");
+        for (final int index : package_index_table) {
+            final String package_name = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
+            buf.append("  ").append(Utility.compactClassName(package_name, false)).append("\n");
+        }
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this attribute
+     */
+    @Override
+    public Attribute copy( final ConstantPool _constant_pool ) {
+        final ModulePackages c = (ModulePackages) clone();
+        if (package_index_table != null) {
+            c.package_index_table = new int[package_index_table.length];
+            System.arraycopy(package_index_table, 0, c.package_index_table, 0,
+                    package_index_table.length);
+        }
+        c.setConstantPool(_constant_pool);
+        return c;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModuleProvides.java b/src/main/java/org/apache/bcel/classfile/ModuleProvides.java
new file mode 100644
index 0000000..4edebf5
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModuleProvides.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class represents an entry in the provides table of the Module attribute.
+ * Each entry describes a service implementation that the parent module provides.
+ *
+ * @see   Module
+ * @since 6.4
+ */
+public final class ModuleProvides implements Cloneable, Node {
+
+    private int provides_index;  // points to CONSTANT_Class_info
+    private int provides_with_count;
+    private int provides_with_index[];  // points to CONSTANT_Class_info
+
+
+    /**
+     * Construct object from file stream.
+     *
+     * @param file Input stream
+     * @throws IOException if an I/O Exception occurs in readUnsignedShort
+     */
+    ModuleProvides(final DataInput file) throws IOException {
+        provides_index = file.readUnsignedShort();
+        provides_with_count = file.readUnsignedShort();
+        provides_with_index = new int[provides_with_count];
+        for (int i = 0; i < provides_with_count; i++) {
+            provides_with_index[i] = file.readUnsignedShort();
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModuleProvides(this);
+    }
+
+    // TODO add more getters and setters?
+
+    /**
+     * Dump table entry to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException if an I/O Exception occurs in writeShort
+     */
+    public final void dump( final DataOutputStream file ) throws IOException {
+        file.writeShort(provides_index);
+        file.writeShort(provides_with_count);
+        for (final int entry : provides_with_index) {
+            file.writeShort(entry);
+        }
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return "provides(" + provides_index + ", " + provides_with_count + ", ...)";
+    }
+
+
+    /**
+     * @return Resolved string representation
+     */
+    public final String toString( final ConstantPool constant_pool ) {
+        final StringBuilder buf = new StringBuilder();
+        final String interface_name = constant_pool.constantToString(provides_index, Const.CONSTANT_Class);
+        buf.append(Utility.compactClassName(interface_name, false));
+        buf.append(", with(").append(provides_with_count).append("):\n");
+        for (final int index : provides_with_index) {
+            final String class_name = constant_pool.getConstantString(index, Const.CONSTANT_Class);
+            buf.append("      ").append(Utility.compactClassName(class_name, false)).append("\n");
+        }
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this object
+     */
+    public ModuleProvides copy() {
+        try {
+            return (ModuleProvides) clone();
+        } catch (final CloneNotSupportedException e) {
+            // TODO should this throw?
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/ModuleRequires.java b/src/main/java/org/apache/bcel/classfile/ModuleRequires.java
new file mode 100644
index 0000000..674ce1e
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/ModuleRequires.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class represents an entry in the requires table of the Module attribute.
+ * Each entry describes a module on which the parent module depends.
+ *
+ * @see   Module
+ * @since 6.4
+ */
+public final class ModuleRequires implements Cloneable, Node {
+
+    private int requires_index;  // points to CONSTANT_Module_info
+    private int requires_flags;
+    private int requires_version_index;  // either 0 or points to CONSTANT_Utf8_info
+
+
+    /**
+     * Construct object from file stream.
+     *
+     * @param file Input stream
+     * @throws IOException if an I/O Exception occurs in readUnsignedShort
+     */
+    ModuleRequires(final DataInput file) throws IOException {
+        requires_index = file.readUnsignedShort();
+        requires_flags = file.readUnsignedShort();
+        requires_version_index = file.readUnsignedShort();
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitModuleRequires(this);
+    }
+
+    // TODO add more getters and setters?
+
+    /**
+     * Dump table entry to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException if an I/O Exception occurs in writeShort
+     */
+    public final void dump( final DataOutputStream file ) throws IOException {
+        file.writeShort(requires_index);
+        file.writeShort(requires_flags);
+        file.writeShort(requires_version_index);
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return "requires(" + requires_index + ", " + String.format("%04x", requires_flags) + ", " + requires_version_index + ")";
+    }
+
+
+    /**
+     * @return Resolved string representation
+     */
+    public final String toString( final ConstantPool constant_pool ) {
+        final StringBuilder buf = new StringBuilder();
+        final String module_name = constant_pool.constantToString(requires_index, Const.CONSTANT_Module);
+        buf.append(Utility.compactClassName(module_name, false));
+        buf.append(", ").append(String.format("%04x", requires_flags));
+        final String version = (requires_version_index == 0 ? "0" : constant_pool.getConstantString(requires_version_index, Const.CONSTANT_Utf8));
+        buf.append(", ").append(version);
+        return buf.toString();
+    }
+
+
+    /**
+     * @return deep copy of this object
+     */
+    public ModuleRequires copy() {
+        try {
+            return (ModuleRequires) clone();
+        } catch (final CloneNotSupportedException e) {
+            // TODO should this throw?
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/NestHost.java b/src/main/java/org/apache/bcel/classfile/NestHost.java
new file mode 100644
index 0000000..44843c2
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/NestHost.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class is derived from <em>Attribute</em> and records the nest host of the nest
+ * to which the current class or interface claims to belong.
+ * There may be at most one NestHost attribute in a ClassFile structure.
+ *
+ * @see     Attribute
+ */
+public final class NestHost extends Attribute {
+
+    private int host_class_index;
+
+
+    /**
+     * Initialize from another object. Note that both objects use the same
+     * references (shallow copy). Use copy() for a physical copy.
+     */
+    public NestHost(final NestHost c) {
+        this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
+    }
+
+
+    /**
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param int Host class index
+     * @param constant_pool Array of constants
+     */
+    public NestHost(final int name_index, final int length, final int host_class_index,
+            final ConstantPool constant_pool) {
+        super(Const.ATTR_NEST_MEMBERS, name_index, length, constant_pool);
+        this.host_class_index = host_class_index;
+    }
+
+
+    /**
+     * Construct object from input stream.
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param input Input stream
+     * @param constant_pool Array of constants
+     * @throws IOException
+     */
+    NestHost(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
+        this(name_index, length, 0, constant_pool);
+        host_class_index = input.readUnsignedShort();
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitNestHost(this);
+    }
+
+
+    /**
+     * Dump NestHost attribute to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException
+     */
+    @Override
+    public final void dump( final DataOutputStream file ) throws IOException {
+        super.dump(file);
+        file.writeShort(host_class_index);
+    }
+
+
+    /**
+     * @return index into constant pool of host class name.
+     */
+    public final int getHostClassIndex() {
+        return host_class_index;
+    }
+
+
+    /**
+     * @param int the host class index
+     */
+    public final void setHostClassIndex( final int host_class_index ) {
+        this.host_class_index = host_class_index;
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("NestHost: ");
+        final String class_name = super.getConstantPool().getConstantString(host_class_index, Const.CONSTANT_Class);
+        buf.append(Utility.compactClassName(class_name, false));
+        return buf.toString();
+    }
+
+
+    /**
+     * @return deep copy of this attribute
+     */
+    @Override
+    public Attribute copy( final ConstantPool _constant_pool ) {
+        final NestHost c = (NestHost) clone();
+        c.setConstantPool(_constant_pool);
+        return c;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/NestMembers.java b/src/main/java/org/apache/bcel/classfile/NestMembers.java
new file mode 100644
index 0000000..da9b6b4
--- /dev/null
+++ b/src/main/java/org/apache/bcel/classfile/NestMembers.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Const;
+
+/**
+ * This class is derived from <em>Attribute</em> and records the classes and interfaces that
+ * are authorized to claim membership in the nest hosted by the current class or interface.
+ * There may be at most one NestMembers attribute in a ClassFile structure.
+ *
+ * @see     Attribute
+ */
+public final class NestMembers extends Attribute {
+
+    private int[] classes;
+
+
+    /**
+     * Initialize from another object. Note that both objects use the same
+     * references (shallow copy). Use copy() for a physical copy.
+     */
+    public NestMembers(final NestMembers c) {
+        this(c.getNameIndex(), c.getLength(), c.getClasses(), c.getConstantPool());
+    }
+
+
+    /**
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param classes Table of indices in constant pool
+     * @param constant_pool Array of constants
+     */
+    public NestMembers(final int name_index, final int length, final int[] classes,
+            final ConstantPool constant_pool) {
+        super(Const.ATTR_NEST_MEMBERS, name_index, length, constant_pool);
+        this.classes = classes != null ? classes : new int[0];
+    }
+
+
+    /**
+     * Construct object from input stream.
+     * @param name_index Index in constant pool
+     * @param length Content length in bytes
+     * @param input Input stream
+     * @param constant_pool Array of constants
+     * @throws IOException
+     */
+    NestMembers(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
+        this(name_index, length, (int[]) null, constant_pool);
+        final int number_of_classes = input.readUnsignedShort();
+        classes = new int[number_of_classes];
+        for (int i = 0; i < number_of_classes; i++) {
+            classes[i] = input.readUnsignedShort();
+        }
+    }
+
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    @Override
+    public void accept( final Visitor v ) {
+        v.visitNestMembers(this);
+    }
+
+
+    /**
+     * Dump NestMembers attribute to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throws IOException
+     */
+    @Override
+    public final void dump( final DataOutputStream file ) throws IOException {
+        super.dump(file);
+        file.writeShort(classes.length);
+        for (final int index : classes) {
+            file.writeShort(index);
+        }
+    }
+
+
+    /**
+     * @return array of indices into constant pool of class names.
+     */
+    public final int[] getClasses() {
+        return classes;
+    }
+
+
+    /**
+     * @return Length of classes table.
+     */
+    public final int getNumberClasses() {
+        return classes == null ? 0 : classes.length;
+    }
+
+
+    /**
+     * @return string array of class names
+     */
+    public final String[] getClassNames() {
+        final String[] names = new String[classes.length];
+        for (int i = 0; i < classes.length; i++) {
+            names[i] = super.getConstantPool().getConstantString(classes[i],
+                    Const.CONSTANT_Class).replace('/', '.');
+        }
+        return names;
+    }
+
+
+    /**
+     * @param classes the list of class indexes
+     * Also redefines number_of_classes according to table length.
+     */
+    public final void setClasses( final int[] classes ) {
+        this.classes = classes != null ? classes : new int[0];
+    }
+
+
+    /**
+     * @return String representation, i.e., a list of classes.
+     */
+    @Override
+    public final String toString() {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("NestMembers(");
+        buf.append(classes.length);
+        buf.append("):\n");
+        for (final int index : classes) {
+            final String class_name = super.getConstantPool().getConstantString(index, Const.CONSTANT_Class);
+            buf.append("  ").append(Utility.compactClassName(class_name, false)).append("\n");
+        }
+        return buf.substring(0, buf.length()-1); // remove the last newline
+    }
+
+
+    /**
+     * @return deep copy of this attribute
+     */
+    @Override
+    public Attribute copy( final ConstantPool _constant_pool ) {
+        final NestMembers c = (NestMembers) clone();
+        if (classes != null) {
+            c.classes = new int[classes.length];
+            System.arraycopy(classes, 0, c.classes, 0,
+                    classes.length);
+        }
+        c.setConstantPool(_constant_pool);
+        return c;
+    }
+}
diff --git a/src/main/java/org/apache/bcel/classfile/Visitor.java b/src/main/java/org/apache/bcel/classfile/Visitor.java
index b8b7d61..1fb2943 100644
--- a/src/main/java/org/apache/bcel/classfile/Visitor.java
+++ b/src/main/java/org/apache/bcel/classfile/Visitor.java
@@ -132,6 +132,13 @@ public interface Visitor
     void visitMethodParameters(MethodParameters obj);
 
     /**
+     * @since 6.4
+     */
+    default void visitMethodParameter(MethodParameter obj) {
+        // empty
+    }
+
+    /**
      * @since 6.0
      */
     void visitConstantMethodType(ConstantMethodType obj);
@@ -162,4 +169,49 @@ public interface Visitor
     default void visitConstantDynamic(ConstantDynamic constantDynamic) {
         // empty
     }
+
+    /**
+     * @since 6.4
+     */
+    void visitModule(Module constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModuleRequires(ModuleRequires constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModuleExports(ModuleExports constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModuleOpens(ModuleOpens constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModuleProvides(ModuleProvides constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModulePackages(ModulePackages constantModule);
+
+    /**
+     * @since 6.4
+     */
+    void visitModuleMainClass(ModuleMainClass obj);
+
+    /**
+     * @since 6.4
+     */
+    void visitNestHost(NestHost obj);
+
+    /**
+     * @since 6.4
+     */
+    void visitNestMembers(NestMembers obj);
 }
diff --git a/src/main/java/org/apache/bcel/generic/ConstantPoolGen.java b/src/main/java/org/apache/bcel/generic/ConstantPoolGen.java
index 88e8f40..fd0af47 100644
--- a/src/main/java/org/apache/bcel/generic/ConstantPoolGen.java
+++ b/src/main/java/org/apache/bcel/generic/ConstantPoolGen.java
@@ -193,6 +193,10 @@ public class ConstantPoolGen {
                 // TODO should this be handled somehow?
             } else if (c instanceof org.apache.bcel.classfile.ConstantMethodHandle) {
                 // TODO should this be handled somehow?
+            } else if (c instanceof org.apache.bcel.classfile.ConstantModule) {
+                // TODO should this be handled somehow?
+            } else if (c instanceof org.apache.bcel.classfile.ConstantPackage) {
+                // TODO should this be handled somehow?
             } else {
                 assert false : "Unexpected constant type: " + c.getClass().getName();
             }
diff --git a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
index 9409428..16031ba 100644
--- a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
+++ b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
@@ -54,6 +54,7 @@ import org.apache.bcel.classfile.LocalVariableTable;
 import org.apache.bcel.classfile.LocalVariableTypeTable;
 import org.apache.bcel.classfile.Method;
 import org.apache.bcel.classfile.MethodParameters;
+import org.apache.bcel.classfile.NestMembers;
 import org.apache.bcel.classfile.Node;
 import org.apache.bcel.classfile.ParameterAnnotationEntry;
 import org.apache.bcel.classfile.ParameterAnnotations;
@@ -403,4 +404,12 @@ public class StringRepresentation extends org.apache.bcel.classfile.EmptyVisitor
     public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
         tostring = toString(obj);
     }
+
+    /**
+     * @since 6.4
+     */
+    @Override
+    public void visitNestMembers(final NestMembers obj) {
+        tostring = toString(obj);
+    }
 }
diff --git a/src/test/java/org/apache/bcel/visitors/CounterVisitor.java b/src/test/java/org/apache/bcel/visitors/CounterVisitor.java
index 3b2a22b..866d619 100644
--- a/src/test/java/org/apache/bcel/visitors/CounterVisitor.java
+++ b/src/test/java/org/apache/bcel/visitors/CounterVisitor.java
@@ -56,7 +56,17 @@ import org.apache.bcel.classfile.LocalVariable;
 import org.apache.bcel.classfile.LocalVariableTable;
 import org.apache.bcel.classfile.LocalVariableTypeTable;
 import org.apache.bcel.classfile.Method;
+import org.apache.bcel.classfile.MethodParameter;
 import org.apache.bcel.classfile.MethodParameters;
+import org.apache.bcel.classfile.Module;
+import org.apache.bcel.classfile.ModuleExports;
+import org.apache.bcel.classfile.ModuleOpens;
+import org.apache.bcel.classfile.ModuleProvides;
+import org.apache.bcel.classfile.ModuleRequires;
+import org.apache.bcel.classfile.ModuleMainClass;
+import org.apache.bcel.classfile.ModulePackages;
+import org.apache.bcel.classfile.NestHost;
+import org.apache.bcel.classfile.NestMembers;
 import org.apache.bcel.classfile.ParameterAnnotationEntry;
 import org.apache.bcel.classfile.ParameterAnnotations;
 import org.apache.bcel.classfile.Signature;
@@ -150,6 +160,9 @@ public class CounterVisitor implements Visitor
     public int bootstrapMethodsCount = 0;
 
     /** @since 6.0 */
+    public int methodParameterCount = 0;
+
+    /** @since 6.0 */
     public int methodParametersCount = 0;
 
     /** @since 6.0 */
@@ -163,6 +176,33 @@ public class CounterVisitor implements Visitor
 
     /** @since 6.3 */
     public int constantDynamicCount = 0;
+
+    /** @since 6.4 */
+    public int moduleCount = 0;
+
+    /** @since 6.4 */
+    public int moduleExportsCount = 0;
+
+    /** @since 6.4 */
+    public int moduleOpensCount = 0;
+
+    /** @since 6.4 */
+    public int moduleProvidesCount = 0;
+
+    /** @since 6.4 */
+    public int moduleRequiresCount = 0;
+
+    /** @since 6.4 */
+    public int moduleMainClassCount = 0;
+
+    /** @since 6.4 */
+    public int modulePackagesCount = 0;
+
+    /** @since 6.4 */
+    public int nestHostCount = 0;
+
+    /** @since 6.4 */
+    public int nestMembersCount = 0;
     // CHECKSTYLE:ON
 
 
@@ -403,6 +443,13 @@ public class CounterVisitor implements Visitor
 
     /** @since 6.0 */
     @Override
+    public void visitMethodParameter(final MethodParameter obj)
+    {
+        methodParameterCount++;
+    }
+
+    /** @since 6.0 */
+    @Override
     public void visitMethodParameters(final MethodParameters obj)
     {
         methodParametersCount++;
@@ -450,4 +497,58 @@ public class CounterVisitor implements Visitor
     public void visitConstantDynamic(final ConstantDynamic constantDynamic) {
         constantDynamicCount++;
     }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModule(final Module obj) {
+        moduleCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleExports(final ModuleExports obj) {
+        moduleExportsCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleOpens(final ModuleOpens obj) {
+        moduleOpensCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleProvides(final ModuleProvides obj) {
+        moduleProvidesCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleRequires(final ModuleRequires obj) {
+        moduleRequiresCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModuleMainClass(final ModuleMainClass obj) {
+        moduleMainClassCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitModulePackages(final ModulePackages obj) {
+        modulePackagesCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestHost(final NestHost obj) {
+        nestHostCount++;
+    }
+
+    /** @since 6.4 */
+    @Override
+    public void visitNestMembers(final NestMembers obj) {
+        nestMembersCount++;
+    }
 }