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
commit c4d889aca20a9ac516b2b06f136e13dd2ae5a688 Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Sat Apr 9 13:48:12 2022 -0400 Checkstyle Use LF. --- NOTICE.txt | 10 +- .../apache/bcel/classfile/DescendingVisitor.java | 1312 ++++++++++---------- .../org/apache/bcel/classfile/FieldOrMethod.java | 588 ++++----- .../org/apache/bcel/generic/INVOKEDYNAMIC.java | 296 ++--- .../org/apache/bcel/generic/InstructionHandle.java | 654 +++++----- .../org/apache/bcel/util/ModularRuntimeImage.java | 304 ++--- 6 files changed, 1582 insertions(+), 1582 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index ee4e9fba..3cc409c3 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ -Apache Commons BCEL -Copyright 2004-2022 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (https://www.apache.org/). +Apache Commons BCEL +Copyright 2004-2022 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). diff --git a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java index e355a648..87e5d5d2 100644 --- a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java +++ b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java @@ -1,656 +1,656 @@ -/* - * 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.util.Stack; - -/** - * Traverses a JavaClass with another Visitor object 'piggy-backed' that is - * applied to all components of a JavaClass object. I.e. this class supplies the - * traversal strategy, other classes can make use of it. - * - */ -public class DescendingVisitor implements Visitor -{ - private final JavaClass clazz; - - private final Visitor visitor; - - private final Stack<Object> stack = new Stack<>(); - - /** - * @return container of current entitity, i.e., predecessor during traversal - */ - public Object predecessor() - { - return predecessor(0); - } - - /** - * @param level - * nesting level, i.e., 0 returns the direct predecessor - * @return container of current entitity, i.e., predecessor during traversal - */ - public Object predecessor(final int level) - { - final int size = stack.size(); - if (size < 2 || level < 0) - { - return null; - } - return stack.elementAt(size - (level + 2)); // size - 1 == current - } - - /** - * @return current object - */ - public Object current() - { - return stack.peek(); - } - - /** - * @param clazz - * Class to traverse - * @param visitor - * visitor object to apply to all components - */ - public DescendingVisitor(final JavaClass clazz, final Visitor visitor) - { - this.clazz = clazz; - this.visitor = visitor; - } - - /** - * Start traversal. - */ - public void visit() - { - clazz.accept(this); - } - - @Override - public void visitJavaClass(final JavaClass _clazz) - { - stack.push(_clazz); - _clazz.accept(visitor); - final Field[] fields = _clazz.getFields(); - for (final Field field : fields) { - field.accept(this); - } - final Method[] methods = _clazz.getMethods(); - for (final Method method : methods) { - method.accept(this); - } - final Attribute[] attributes = _clazz.getAttributes(); - for (final Attribute attribute : attributes) { - attribute.accept(this); - } - _clazz.getConstantPool().accept(this); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitAnnotation(final Annotations annotation) - { - stack.push(annotation); - annotation.accept(visitor); - final AnnotationEntry[] entries = annotation.getAnnotationEntries(); - for (final AnnotationEntry entrie : entries) { - entrie.accept(this); - } - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitAnnotationEntry(final AnnotationEntry annotationEntry) - { - stack.push(annotationEntry); - annotationEntry.accept(visitor); - stack.pop(); - } - - @Override - public void visitField(final Field field) - { - stack.push(field); - field.accept(visitor); - final Attribute[] attributes = field.getAttributes(); - for (final Attribute attribute : attributes) { - attribute.accept(this); - } - stack.pop(); - } - - @Override - public void visitConstantValue(final ConstantValue cv) - { - stack.push(cv); - cv.accept(visitor); - stack.pop(); - } - - @Override - public void visitMethod(final Method method) - { - stack.push(method); - method.accept(visitor); - final Attribute[] attributes = method.getAttributes(); - for (final Attribute attribute : attributes) { - attribute.accept(this); - } - stack.pop(); - } - - @Override - public void visitExceptionTable(final ExceptionTable table) - { - stack.push(table); - table.accept(visitor); - stack.pop(); - } - - @Override - public void visitCode(final Code code) - { - stack.push(code); - code.accept(visitor); - final CodeException[] table = code.getExceptionTable(); - for (final CodeException element : table) { - element.accept(this); - } - final Attribute[] attributes = code.getAttributes(); - for (final Attribute attribute : attributes) { - attribute.accept(this); - } - stack.pop(); - } - - @Override - public void visitCodeException(final CodeException ce) - { - stack.push(ce); - ce.accept(visitor); - stack.pop(); - } - - @Override - public void visitLineNumberTable(final LineNumberTable table) - { - stack.push(table); - table.accept(visitor); - final LineNumber[] numbers = table.getLineNumberTable(); - for (final LineNumber number : numbers) { - number.accept(this); - } - stack.pop(); - } - - @Override - public void visitLineNumber(final LineNumber number) - { - stack.push(number); - number.accept(visitor); - stack.pop(); - } - - @Override - public void visitLocalVariableTable(final LocalVariableTable table) - { - stack.push(table); - table.accept(visitor); - final LocalVariable[] vars = table.getLocalVariableTable(); - for (final LocalVariable var : vars) { - var.accept(this); - } - stack.pop(); - } - - @Override - public void visitStackMap(final StackMap table) - { - stack.push(table); - table.accept(visitor); - final StackMapEntry[] vars = table.getStackMap(); - for (final StackMapEntry var : vars) { - var.accept(this); - } - stack.pop(); - } - - @Override - public void visitStackMapEntry(final StackMapEntry var) - { - stack.push(var); - var.accept(visitor); - stack.pop(); - } - - @Override - public void visitLocalVariable(final LocalVariable var) - { - stack.push(var); - var.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantPool(final ConstantPool cp) - { - stack.push(cp); - cp.accept(visitor); - final Constant[] constants = cp.getConstantPool(); - for (int i = 1; i < constants.length; i++) - { - if (constants[i] != null) - { - constants[i].accept(this); - } - } - stack.pop(); - } - - @Override - public void visitConstantClass(final ConstantClass constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantDouble(final ConstantDouble constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantFieldref(final ConstantFieldref constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantFloat(final ConstantFloat constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantInteger(final ConstantInteger constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantInterfaceMethodref( - final ConstantInterfaceMethodref constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitConstantInvokeDynamic( - final ConstantInvokeDynamic constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantLong(final ConstantLong constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantMethodref(final ConstantMethodref constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantNameAndType(final ConstantNameAndType constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantString(final ConstantString constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitConstantUtf8(final ConstantUtf8 constant) - { - stack.push(constant); - constant.accept(visitor); - stack.pop(); - } - - @Override - public void visitInnerClasses(final InnerClasses ic) - { - stack.push(ic); - ic.accept(visitor); - final InnerClass[] ics = ic.getInnerClasses(); - for (final InnerClass ic2 : ics) { - ic2.accept(this); - } - stack.pop(); - } - - @Override - public void visitInnerClass(final InnerClass inner) - { - stack.push(inner); - inner.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitBootstrapMethods(final BootstrapMethods bm) - { - stack.push(bm); - bm.accept(visitor); - // BootstrapMethod[] bms = bm.getBootstrapMethods(); - // for (int i = 0; i < bms.length; i++) - // { - // bms[i].accept(this); - // } - stack.pop(); - } - - @Override - public void visitDeprecated(final Deprecated attribute) - { - stack.push(attribute); - attribute.accept(visitor); - stack.pop(); - } - - @Override - public void visitSignature(final Signature attribute) - { - stack.push(attribute); - attribute.accept(visitor); - stack.pop(); - } - - @Override - public void visitSourceFile(final SourceFile attribute) - { - stack.push(attribute); - attribute.accept(visitor); - stack.pop(); - } - - @Override - public void visitSynthetic(final Synthetic attribute) - { - stack.push(attribute); - attribute.accept(visitor); - stack.pop(); - } - - @Override - public void visitUnknown(final Unknown attribute) - { - stack.push(attribute); - attribute.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitAnnotationDefault(final AnnotationDefault obj) - { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitEnclosingMethod(final EnclosingMethod obj) - { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) - { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitParameterAnnotation(final ParameterAnnotations obj) - { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** - * @since 6.0 - */ - @Override - public void visitMethodParameters(final MethodParameters obj) - { - stack.push(obj); - obj.accept(visitor); - final MethodParameter[] table = obj.getParameters(); - for (final MethodParameter element : table) { - element.accept(this); - } - stack.pop(); - } - - /** - * @since 6.4.0 - */ - @Override - public void visitMethodParameter(final MethodParameter obj) - { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.0 */ - @Override - public void visitConstantMethodType(final ConstantMethodType obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.0 */ - @Override - public void visitConstantMethodHandle(final ConstantMethodHandle obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.0 */ - @Override - public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.1 */ - @Override - public void visitConstantPackage(final ConstantPackage obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.1 */ - @Override - public void visitConstantModule(final ConstantModule obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.3 */ - @Override - public void visitConstantDynamic(final ConstantDynamic obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @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); - } - final ModuleOpens[] otable = obj.getOpensTable(); - for (final ModuleOpens element : otable) { - element.accept(this); - } - final ModuleProvides[] ptable = obj.getProvidesTable(); - for (final ModuleProvides element : ptable) { - element.accept(this); - } - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModuleRequires(final ModuleRequires obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModuleExports(final ModuleExports obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModuleOpens(final ModuleOpens obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModuleProvides(final ModuleProvides obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModulePackages(final ModulePackages obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitModuleMainClass(final ModuleMainClass obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitNestHost(final NestHost obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } - - /** @since 6.4.0 */ - @Override - public void visitNestMembers(final NestMembers obj) { - stack.push(obj); - obj.accept(visitor); - stack.pop(); - } -} +/* + * 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.util.Stack; + +/** + * Traverses a JavaClass with another Visitor object 'piggy-backed' that is + * applied to all components of a JavaClass object. I.e. this class supplies the + * traversal strategy, other classes can make use of it. + * + */ +public class DescendingVisitor implements Visitor +{ + private final JavaClass clazz; + + private final Visitor visitor; + + private final Stack<Object> stack = new Stack<>(); + + /** + * @return container of current entitity, i.e., predecessor during traversal + */ + public Object predecessor() + { + return predecessor(0); + } + + /** + * @param level + * nesting level, i.e., 0 returns the direct predecessor + * @return container of current entitity, i.e., predecessor during traversal + */ + public Object predecessor(final int level) + { + final int size = stack.size(); + if (size < 2 || level < 0) + { + return null; + } + return stack.elementAt(size - (level + 2)); // size - 1 == current + } + + /** + * @return current object + */ + public Object current() + { + return stack.peek(); + } + + /** + * @param clazz + * Class to traverse + * @param visitor + * visitor object to apply to all components + */ + public DescendingVisitor(final JavaClass clazz, final Visitor visitor) + { + this.clazz = clazz; + this.visitor = visitor; + } + + /** + * Start traversal. + */ + public void visit() + { + clazz.accept(this); + } + + @Override + public void visitJavaClass(final JavaClass _clazz) + { + stack.push(_clazz); + _clazz.accept(visitor); + final Field[] fields = _clazz.getFields(); + for (final Field field : fields) { + field.accept(this); + } + final Method[] methods = _clazz.getMethods(); + for (final Method method : methods) { + method.accept(this); + } + final Attribute[] attributes = _clazz.getAttributes(); + for (final Attribute attribute : attributes) { + attribute.accept(this); + } + _clazz.getConstantPool().accept(this); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitAnnotation(final Annotations annotation) + { + stack.push(annotation); + annotation.accept(visitor); + final AnnotationEntry[] entries = annotation.getAnnotationEntries(); + for (final AnnotationEntry entrie : entries) { + entrie.accept(this); + } + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitAnnotationEntry(final AnnotationEntry annotationEntry) + { + stack.push(annotationEntry); + annotationEntry.accept(visitor); + stack.pop(); + } + + @Override + public void visitField(final Field field) + { + stack.push(field); + field.accept(visitor); + final Attribute[] attributes = field.getAttributes(); + for (final Attribute attribute : attributes) { + attribute.accept(this); + } + stack.pop(); + } + + @Override + public void visitConstantValue(final ConstantValue cv) + { + stack.push(cv); + cv.accept(visitor); + stack.pop(); + } + + @Override + public void visitMethod(final Method method) + { + stack.push(method); + method.accept(visitor); + final Attribute[] attributes = method.getAttributes(); + for (final Attribute attribute : attributes) { + attribute.accept(this); + } + stack.pop(); + } + + @Override + public void visitExceptionTable(final ExceptionTable table) + { + stack.push(table); + table.accept(visitor); + stack.pop(); + } + + @Override + public void visitCode(final Code code) + { + stack.push(code); + code.accept(visitor); + final CodeException[] table = code.getExceptionTable(); + for (final CodeException element : table) { + element.accept(this); + } + final Attribute[] attributes = code.getAttributes(); + for (final Attribute attribute : attributes) { + attribute.accept(this); + } + stack.pop(); + } + + @Override + public void visitCodeException(final CodeException ce) + { + stack.push(ce); + ce.accept(visitor); + stack.pop(); + } + + @Override + public void visitLineNumberTable(final LineNumberTable table) + { + stack.push(table); + table.accept(visitor); + final LineNumber[] numbers = table.getLineNumberTable(); + for (final LineNumber number : numbers) { + number.accept(this); + } + stack.pop(); + } + + @Override + public void visitLineNumber(final LineNumber number) + { + stack.push(number); + number.accept(visitor); + stack.pop(); + } + + @Override + public void visitLocalVariableTable(final LocalVariableTable table) + { + stack.push(table); + table.accept(visitor); + final LocalVariable[] vars = table.getLocalVariableTable(); + for (final LocalVariable var : vars) { + var.accept(this); + } + stack.pop(); + } + + @Override + public void visitStackMap(final StackMap table) + { + stack.push(table); + table.accept(visitor); + final StackMapEntry[] vars = table.getStackMap(); + for (final StackMapEntry var : vars) { + var.accept(this); + } + stack.pop(); + } + + @Override + public void visitStackMapEntry(final StackMapEntry var) + { + stack.push(var); + var.accept(visitor); + stack.pop(); + } + + @Override + public void visitLocalVariable(final LocalVariable var) + { + stack.push(var); + var.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantPool(final ConstantPool cp) + { + stack.push(cp); + cp.accept(visitor); + final Constant[] constants = cp.getConstantPool(); + for (int i = 1; i < constants.length; i++) + { + if (constants[i] != null) + { + constants[i].accept(this); + } + } + stack.pop(); + } + + @Override + public void visitConstantClass(final ConstantClass constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantDouble(final ConstantDouble constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantFieldref(final ConstantFieldref constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantFloat(final ConstantFloat constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantInteger(final ConstantInteger constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantInterfaceMethodref( + final ConstantInterfaceMethodref constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitConstantInvokeDynamic( + final ConstantInvokeDynamic constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantLong(final ConstantLong constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantMethodref(final ConstantMethodref constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantNameAndType(final ConstantNameAndType constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantString(final ConstantString constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitConstantUtf8(final ConstantUtf8 constant) + { + stack.push(constant); + constant.accept(visitor); + stack.pop(); + } + + @Override + public void visitInnerClasses(final InnerClasses ic) + { + stack.push(ic); + ic.accept(visitor); + final InnerClass[] ics = ic.getInnerClasses(); + for (final InnerClass ic2 : ics) { + ic2.accept(this); + } + stack.pop(); + } + + @Override + public void visitInnerClass(final InnerClass inner) + { + stack.push(inner); + inner.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitBootstrapMethods(final BootstrapMethods bm) + { + stack.push(bm); + bm.accept(visitor); + // BootstrapMethod[] bms = bm.getBootstrapMethods(); + // for (int i = 0; i < bms.length; i++) + // { + // bms[i].accept(this); + // } + stack.pop(); + } + + @Override + public void visitDeprecated(final Deprecated attribute) + { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + @Override + public void visitSignature(final Signature attribute) + { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + @Override + public void visitSourceFile(final SourceFile attribute) + { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + @Override + public void visitSynthetic(final Synthetic attribute) + { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + @Override + public void visitUnknown(final Unknown attribute) + { + stack.push(attribute); + attribute.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitAnnotationDefault(final AnnotationDefault obj) + { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitEnclosingMethod(final EnclosingMethod obj) + { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) + { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitParameterAnnotation(final ParameterAnnotations obj) + { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** + * @since 6.0 + */ + @Override + public void visitMethodParameters(final MethodParameters obj) + { + stack.push(obj); + obj.accept(visitor); + final MethodParameter[] table = obj.getParameters(); + for (final MethodParameter element : table) { + element.accept(this); + } + stack.pop(); + } + + /** + * @since 6.4.0 + */ + @Override + public void visitMethodParameter(final MethodParameter obj) + { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.0 */ + @Override + public void visitConstantMethodType(final ConstantMethodType obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.0 */ + @Override + public void visitConstantMethodHandle(final ConstantMethodHandle obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.0 */ + @Override + public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.1 */ + @Override + public void visitConstantPackage(final ConstantPackage obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.1 */ + @Override + public void visitConstantModule(final ConstantModule obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.3 */ + @Override + public void visitConstantDynamic(final ConstantDynamic obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @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); + } + final ModuleOpens[] otable = obj.getOpensTable(); + for (final ModuleOpens element : otable) { + element.accept(this); + } + final ModuleProvides[] ptable = obj.getProvidesTable(); + for (final ModuleProvides element : ptable) { + element.accept(this); + } + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModuleRequires(final ModuleRequires obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModuleExports(final ModuleExports obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModuleOpens(final ModuleOpens obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModuleProvides(final ModuleProvides obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModulePackages(final ModulePackages obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitModuleMainClass(final ModuleMainClass obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @Override + public void visitNestHost(final NestHost obj) { + stack.push(obj); + obj.accept(visitor); + stack.pop(); + } + + /** @since 6.4.0 */ + @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/FieldOrMethod.java b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java index 4344adad..53c90165 100644 --- a/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java +++ b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java @@ -1,294 +1,294 @@ -/* - * 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.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import org.apache.bcel.Const; - -/** - * Abstract super class for fields and methods. - * - */ -public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected int name_index; // Points to field name in constant pool - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected int signature_index; // Points to encoded signature - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected Attribute[] attributes; // Collection of attributes - - /** - * @deprecated (since 6.0) will be removed (not needed) - */ - @java.lang.Deprecated - protected int attributes_count; // No. of attributes - - // @since 6.0 - private AnnotationEntry[] annotationEntries; // annotations defined on the field or method - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected ConstantPool constant_pool; - - private String signatureAttributeString; - private boolean searchedForSignatureAttribute; - - FieldOrMethod() { - } - - - /** - * Initialize from another object. Note that both objects use the same - * references (shallow copy). Use clone() for a physical copy. - */ - protected FieldOrMethod(final FieldOrMethod c) { - this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c - .getConstantPool()); - } - - - /** - * Construct object from file stream. - * @param file Input stream - * @throws IOException - * @throws ClassFormatException - * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead. - */ - @java.lang.Deprecated - protected FieldOrMethod(final DataInputStream file, final ConstantPool constant_pool) throws IOException, - ClassFormatException { - this((DataInput) file, constant_pool); - } - - /** - * Construct object from file stream. - * @param file Input stream - * @throws IOException - * @throws ClassFormatException - */ - protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException { - this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, - constant_pool); - final int attributes_count = file.readUnsignedShort(); - attributes = new Attribute[attributes_count]; - for (int i = 0; i < attributes_count; i++) { - attributes[i] = Attribute.readAttribute(file, constant_pool); - } - this.attributes_count = attributes_count; // init deprecated field - } - - - /** - * @param access_flags Access rights of method - * @param name_index Points to field name in constant pool - * @param signature_index Points to encoded signature - * @param attributes Collection of attributes - * @param constant_pool Array of constants - */ - protected FieldOrMethod(final int access_flags, final int name_index, final int signature_index, - final Attribute[] attributes, final ConstantPool constant_pool) { - super(access_flags); - this.name_index = name_index; - this.signature_index = signature_index; - this.constant_pool = constant_pool; - setAttributes(attributes); - } - - - /** - * Dump object to file stream on binary format. - * - * @param file Output file stream - * @throws IOException - */ - public final void dump(final DataOutputStream file) throws IOException { - file.writeShort(super.getAccessFlags()); - file.writeShort(name_index); - file.writeShort(signature_index); - file.writeShort(attributes_count); - if (attributes != null) { - for (final Attribute attribute : attributes) { - attribute.dump(file); - } - } - } - - - /** - * @return Collection of object attributes. - */ - public final Attribute[] getAttributes() { - return attributes; - } - - - /** - * @param attributes Collection of object attributes. - */ - public final void setAttributes( final Attribute[] attributes ) { - this.attributes = attributes; - this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field - } - - - /** - * @return Constant pool used by this object. - */ - public final ConstantPool getConstantPool() { - return constant_pool; - } - - - /** - * @param constant_pool Constant pool to be used for this object. - */ - public final void setConstantPool( final ConstantPool constant_pool ) { - this.constant_pool = constant_pool; - } - - - /** - * @return Index in constant pool of object's name. - */ - public final int getNameIndex() { - return name_index; - } - - - /** - * @param name_index Index in constant pool of object's name. - */ - public final void setNameIndex( final int name_index ) { - this.name_index = name_index; - } - - - /** - * @return Index in constant pool of field signature. - */ - public final int getSignatureIndex() { - return signature_index; - } - - - /** - * @param signature_index Index in constant pool of field signature. - */ - public final void setSignatureIndex( final int signature_index ) { - this.signature_index = signature_index; - } - - - /** - * @return Name of object, i.e., method name or field name - */ - public final String getName() { - ConstantUtf8 c; - c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8); - return c.getBytes(); - } - - - /** - * @return String representation of object's type signature (java style) - */ - public final String getSignature() { - ConstantUtf8 c; - c = (ConstantUtf8) constant_pool.getConstant(signature_index, Const.CONSTANT_Utf8); - return c.getBytes(); - } - - - /** - * @return deep copy of this field - */ - protected FieldOrMethod copy_( final ConstantPool _constant_pool ) { - FieldOrMethod c = null; - - try { - c = (FieldOrMethod)clone(); - } catch(final CloneNotSupportedException e) { - // ignored, but will cause NPE ... - } - - c.constant_pool = constant_pool; - c.attributes = new Attribute[attributes.length]; - c.attributes_count = attributes_count; // init deprecated field - - for (int i = 0; i < attributes.length; i++) { - c.attributes[i] = attributes[i].copy(constant_pool); - } - - return c; - } - - /** - * @return Annotations on the field or method - * @since 6.0 - */ - public AnnotationEntry[] getAnnotationEntries() { - if (annotationEntries == null) { - annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes()); - } - - return annotationEntries; - } - - /** - * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature - * may be (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' - * Coded for performance - searches for the attribute only when requested - only searches for it once. - * @since 6.0 - */ - public final String getGenericSignature() - { - if (!searchedForSignatureAttribute) - { - boolean found = false; - for (int i = 0; !found && i < attributes.length; i++) - { - if (attributes[i] instanceof Signature) - { - signatureAttributeString = ((Signature) attributes[i]) - .getSignature(); - found = true; - } - } - searchedForSignatureAttribute = true; - } - return signatureAttributeString; - } -} +/* + * 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.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.bcel.Const; + +/** + * Abstract super class for fields and methods. + * + */ +public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { + + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected int name_index; // Points to field name in constant pool + + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected int signature_index; // Points to encoded signature + + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected Attribute[] attributes; // Collection of attributes + + /** + * @deprecated (since 6.0) will be removed (not needed) + */ + @java.lang.Deprecated + protected int attributes_count; // No. of attributes + + // @since 6.0 + private AnnotationEntry[] annotationEntries; // annotations defined on the field or method + + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected ConstantPool constant_pool; + + private String signatureAttributeString; + private boolean searchedForSignatureAttribute; + + FieldOrMethod() { + } + + + /** + * Initialize from another object. Note that both objects use the same + * references (shallow copy). Use clone() for a physical copy. + */ + protected FieldOrMethod(final FieldOrMethod c) { + this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c + .getConstantPool()); + } + + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + * @throws ClassFormatException + * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead. + */ + @java.lang.Deprecated + protected FieldOrMethod(final DataInputStream file, final ConstantPool constant_pool) throws IOException, + ClassFormatException { + this((DataInput) file, constant_pool); + } + + /** + * Construct object from file stream. + * @param file Input stream + * @throws IOException + * @throws ClassFormatException + */ + protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException { + this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, + constant_pool); + final int attributes_count = file.readUnsignedShort(); + attributes = new Attribute[attributes_count]; + for (int i = 0; i < attributes_count; i++) { + attributes[i] = Attribute.readAttribute(file, constant_pool); + } + this.attributes_count = attributes_count; // init deprecated field + } + + + /** + * @param access_flags Access rights of method + * @param name_index Points to field name in constant pool + * @param signature_index Points to encoded signature + * @param attributes Collection of attributes + * @param constant_pool Array of constants + */ + protected FieldOrMethod(final int access_flags, final int name_index, final int signature_index, + final Attribute[] attributes, final ConstantPool constant_pool) { + super(access_flags); + this.name_index = name_index; + this.signature_index = signature_index; + this.constant_pool = constant_pool; + setAttributes(attributes); + } + + + /** + * Dump object to file stream on binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump(final DataOutputStream file) throws IOException { + file.writeShort(super.getAccessFlags()); + file.writeShort(name_index); + file.writeShort(signature_index); + file.writeShort(attributes_count); + if (attributes != null) { + for (final Attribute attribute : attributes) { + attribute.dump(file); + } + } + } + + + /** + * @return Collection of object attributes. + */ + public final Attribute[] getAttributes() { + return attributes; + } + + + /** + * @param attributes Collection of object attributes. + */ + public final void setAttributes( final Attribute[] attributes ) { + this.attributes = attributes; + this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field + } + + + /** + * @return Constant pool used by this object. + */ + public final ConstantPool getConstantPool() { + return constant_pool; + } + + + /** + * @param constant_pool Constant pool to be used for this object. + */ + public final void setConstantPool( final ConstantPool constant_pool ) { + this.constant_pool = constant_pool; + } + + + /** + * @return Index in constant pool of object's name. + */ + public final int getNameIndex() { + return name_index; + } + + + /** + * @param name_index Index in constant pool of object's name. + */ + public final void setNameIndex( final int name_index ) { + this.name_index = name_index; + } + + + /** + * @return Index in constant pool of field signature. + */ + public final int getSignatureIndex() { + return signature_index; + } + + + /** + * @param signature_index Index in constant pool of field signature. + */ + public final void setSignatureIndex( final int signature_index ) { + this.signature_index = signature_index; + } + + + /** + * @return Name of object, i.e., method name or field name + */ + public final String getName() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return String representation of object's type signature (java style) + */ + public final String getSignature() { + ConstantUtf8 c; + c = (ConstantUtf8) constant_pool.getConstant(signature_index, Const.CONSTANT_Utf8); + return c.getBytes(); + } + + + /** + * @return deep copy of this field + */ + protected FieldOrMethod copy_( final ConstantPool _constant_pool ) { + FieldOrMethod c = null; + + try { + c = (FieldOrMethod)clone(); + } catch(final CloneNotSupportedException e) { + // ignored, but will cause NPE ... + } + + c.constant_pool = constant_pool; + c.attributes = new Attribute[attributes.length]; + c.attributes_count = attributes_count; // init deprecated field + + for (int i = 0; i < attributes.length; i++) { + c.attributes[i] = attributes[i].copy(constant_pool); + } + + return c; + } + + /** + * @return Annotations on the field or method + * @since 6.0 + */ + public AnnotationEntry[] getAnnotationEntries() { + if (annotationEntries == null) { + annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes()); + } + + return annotationEntries; + } + + /** + * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature + * may be (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' + * Coded for performance - searches for the attribute only when requested - only searches for it once. + * @since 6.0 + */ + public final String getGenericSignature() + { + if (!searchedForSignatureAttribute) + { + boolean found = false; + for (int i = 0; !found && i < attributes.length; i++) + { + if (attributes[i] instanceof Signature) + { + signatureAttributeString = ((Signature) attributes[i]) + .getSignature(); + found = true; + } + } + searchedForSignatureAttribute = true; + } + return signatureAttributeString; + } +} diff --git a/src/main/java/org/apache/bcel/generic/INVOKEDYNAMIC.java b/src/main/java/org/apache/bcel/generic/INVOKEDYNAMIC.java index e740e5b2..f4702e87 100644 --- a/src/main/java/org/apache/bcel/generic/INVOKEDYNAMIC.java +++ b/src/main/java/org/apache/bcel/generic/INVOKEDYNAMIC.java @@ -1,148 +1,148 @@ -/* - * 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.generic; - -import java.io.DataOutputStream; -import java.io.IOException; - -import org.apache.bcel.Const; -import org.apache.bcel.ExceptionConst; -import org.apache.bcel.classfile.ConstantInvokeDynamic; -import org.apache.bcel.classfile.ConstantNameAndType; -import org.apache.bcel.classfile.ConstantPool; -import org.apache.bcel.util.ByteSequence; - -/** - * Class for INVOKEDYNAMIC. Not an instance of InvokeInstruction, since that class - * expects to be able to get the class of the method. Ignores the bootstrap - * mechanism entirely. - * - * @see - * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic"> - * The invokedynamic instruction in The Java Virtual Machine Specification</a> - * @since 6.0 - */ -public class INVOKEDYNAMIC extends InvokeInstruction { - - /** - * Empty constructor needed for Instruction.readInstruction. - * Not to be used otherwise. - */ - INVOKEDYNAMIC() { - } - - - public INVOKEDYNAMIC(final int index) { - super(Const.INVOKEDYNAMIC, index); - } - - - /** - * Dump instruction as byte code to stream out. - * @param out Output stream - */ - @Override - public void dump( final DataOutputStream out ) throws IOException { - out.writeByte(super.getOpcode()); - out.writeShort(super.getIndex()); - out.writeByte(0); - out.writeByte(0); - } - - - /** - * Read needed data (i.e., index) from file. - */ - @Override - protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { - super.initFromFile(bytes, wide); - super.setLength(5); - bytes.readByte(); // Skip 0 byte - bytes.readByte(); // Skip 0 byte - } - - - /** - * @return mnemonic for instruction with symbolic references resolved - */ - @Override - public String toString( final ConstantPool cp ) { - return super.toString(cp); - } - - - @Override - public Class<?>[] getExceptions() { - return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, - ExceptionConst.UNSATISFIED_LINK_ERROR, - ExceptionConst.ABSTRACT_METHOD_ERROR, - ExceptionConst.ILLEGAL_ACCESS_ERROR, - ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); - } - - - /** - * Call corresponding visitor method(s). The order is: - * Call visitor methods of implemented interfaces first, then - * call methods according to the class hierarchy in descending order, - * i.e., the most specific visitXXX() call comes last. - * - * @param v Visitor object - */ - @Override - public void accept( final Visitor v ) { - v.visitExceptionThrower(this); - v.visitTypedInstruction(this); - v.visitStackConsumer(this); - v.visitStackProducer(this); - v.visitLoadClass(this); - v.visitCPInstruction(this); - v.visitFieldOrMethod(this); - v.visitInvokeInstruction(this); - v.visitINVOKEDYNAMIC(this); - } - - /** - * Override the parent method because our classname is held elsewhere. - * - * Note: Contrary to this method's name it does not return the classname of the - * invoke target; rather it returns the name of the method that will be used to - * invoke the Lambda method generated by this invoke dynamic instruction. - */ - @Override - public String getClassName( final ConstantPoolGen cpg ) { - final ConstantPool cp = cpg.getConstantPool(); - final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) cp.getConstant(super.getIndex(), Const.CONSTANT_InvokeDynamic); - return ((ConstantNameAndType) cp.getConstant(cid.getNameAndTypeIndex())).getName(cp); - } - - - /** - * Since InvokeDynamic doesn't refer to a reference type, just return java.lang.Object, - * as that is the only type we can say for sure the reference will be. - * - * @param cpg - * the ConstantPoolGen used to create the instruction - * @return an ObjectType for java.lang.Object - * @since 6.1 - */ - @Override - public ReferenceType getReferenceType(final ConstantPoolGen cpg) { - return new ObjectType(Object.class.getName()); - } -} +/* + * 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.generic; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.bcel.Const; +import org.apache.bcel.ExceptionConst; +import org.apache.bcel.classfile.ConstantInvokeDynamic; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.util.ByteSequence; + +/** + * Class for INVOKEDYNAMIC. Not an instance of InvokeInstruction, since that class + * expects to be able to get the class of the method. Ignores the bootstrap + * mechanism entirely. + * + * @see + * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic"> + * The invokedynamic instruction in The Java Virtual Machine Specification</a> + * @since 6.0 + */ +public class INVOKEDYNAMIC extends InvokeInstruction { + + /** + * Empty constructor needed for Instruction.readInstruction. + * Not to be used otherwise. + */ + INVOKEDYNAMIC() { + } + + + public INVOKEDYNAMIC(final int index) { + super(Const.INVOKEDYNAMIC, index); + } + + + /** + * Dump instruction as byte code to stream out. + * @param out Output stream + */ + @Override + public void dump( final DataOutputStream out ) throws IOException { + out.writeByte(super.getOpcode()); + out.writeShort(super.getIndex()); + out.writeByte(0); + out.writeByte(0); + } + + + /** + * Read needed data (i.e., index) from file. + */ + @Override + protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { + super.initFromFile(bytes, wide); + super.setLength(5); + bytes.readByte(); // Skip 0 byte + bytes.readByte(); // Skip 0 byte + } + + + /** + * @return mnemonic for instruction with symbolic references resolved + */ + @Override + public String toString( final ConstantPool cp ) { + return super.toString(cp); + } + + + @Override + public Class<?>[] getExceptions() { + return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, + ExceptionConst.UNSATISFIED_LINK_ERROR, + ExceptionConst.ABSTRACT_METHOD_ERROR, + ExceptionConst.ILLEGAL_ACCESS_ERROR, + ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); + } + + + /** + * Call corresponding visitor method(s). The order is: + * Call visitor methods of implemented interfaces first, then + * call methods according to the class hierarchy in descending order, + * i.e., the most specific visitXXX() call comes last. + * + * @param v Visitor object + */ + @Override + public void accept( final Visitor v ) { + v.visitExceptionThrower(this); + v.visitTypedInstruction(this); + v.visitStackConsumer(this); + v.visitStackProducer(this); + v.visitLoadClass(this); + v.visitCPInstruction(this); + v.visitFieldOrMethod(this); + v.visitInvokeInstruction(this); + v.visitINVOKEDYNAMIC(this); + } + + /** + * Override the parent method because our classname is held elsewhere. + * + * Note: Contrary to this method's name it does not return the classname of the + * invoke target; rather it returns the name of the method that will be used to + * invoke the Lambda method generated by this invoke dynamic instruction. + */ + @Override + public String getClassName( final ConstantPoolGen cpg ) { + final ConstantPool cp = cpg.getConstantPool(); + final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) cp.getConstant(super.getIndex(), Const.CONSTANT_InvokeDynamic); + return ((ConstantNameAndType) cp.getConstant(cid.getNameAndTypeIndex())).getName(cp); + } + + + /** + * Since InvokeDynamic doesn't refer to a reference type, just return java.lang.Object, + * as that is the only type we can say for sure the reference will be. + * + * @param cpg + * the ConstantPoolGen used to create the instruction + * @return an ObjectType for java.lang.Object + * @since 6.1 + */ + @Override + public ReferenceType getReferenceType(final ConstantPoolGen cpg) { + return new ObjectType(Object.class.getName()); + } +} diff --git a/src/main/java/org/apache/bcel/generic/InstructionHandle.java b/src/main/java/org/apache/bcel/generic/InstructionHandle.java index 71e2ed15..1a7f2b3b 100644 --- a/src/main/java/org/apache/bcel/generic/InstructionHandle.java +++ b/src/main/java/org/apache/bcel/generic/InstructionHandle.java @@ -1,327 +1,327 @@ -/* - * 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.generic; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.bcel.classfile.Utility; - -/** - * Instances of this class give users a handle to the instructions contained in - * an InstructionList. Instruction objects may be used more than once within a - * list, this is useful because it saves memory and may be much faster. - * - * Within an InstructionList an InstructionHandle object is wrapped - * around all instructions, i.e., it implements a cell in a - * doubly-linked list. From the outside only the next and the - * previous instruction (handle) are accessible. One - * can traverse the list via an Enumeration returned by - * InstructionList.elements(). - * - * @see Instruction - * @see BranchHandle - * @see InstructionList - */ -public class InstructionHandle { - - /** - * Empty array. - * - * @since 6.6.0 - */ - public static final InstructionHandle[] EMPTY_INSTRUCTION_HANDLE_ARRAY = new InstructionHandle[0]; - - /** - * Empty array. - */ - static final InstructionTargeter[] EMPTY_INSTRUCTION_TARGETER_ARRAY = new InstructionTargeter[0]; - - private InstructionHandle next; - private InstructionHandle prev; - private Instruction instruction; - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected int i_position = -1; // byte code offset of instruction - - private Set<InstructionTargeter> targeters; - private Map<Object, Object> attributes; - - - /** - * Does nothing. - * - * @deprecated Does nothing as of 6.3.1. - */ - @Deprecated - protected void addHandle() { - // noop - } - - public final InstructionHandle getNext() { - return next; - } - - - public final InstructionHandle getPrev() { - return prev; - } - - - public final Instruction getInstruction() { - return instruction; - } - - - /** - * Replace current instruction contained in this handle. - * Old instruction is disposed using Instruction.dispose(). - */ - public void setInstruction( final Instruction i ) { // Overridden in BranchHandle TODO could be package-protected? - if (i == null) { - throw new ClassGenException("Assigning null to handle"); - } - if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) { - throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); - } - if (instruction != null) { - instruction.dispose(); - } - instruction = i; - } - - - /** - * Temporarily swap the current instruction, without disturbing - * anything. Meant to be used by a debugger, implementing - * breakpoints. Current instruction is returned. - * <p> - * Warning: if this is used on a BranchHandle then some methods such as - * getPosition() will still refer to the original cached instruction, whereas - * other BH methods may affect the cache and the replacement instruction. - */ - // See BCEL-273 - // TODO remove this method in any redesign of BCEL - public Instruction swapInstruction( final Instruction i ) { - final Instruction oldInstruction = instruction; - instruction = i; - return oldInstruction; - } - - - /*private*/protected InstructionHandle(final Instruction i) { - setInstruction(i); - } - - /** Factory method. - */ - static InstructionHandle getInstructionHandle( final Instruction i ) { - return new InstructionHandle(i); - } - - - /** - * Called by InstructionList.setPositions when setting the position for every - * instruction. In the presence of variable length instructions `setPositions()' - * performs multiple passes over the instruction list to calculate the - * correct (byte) positions and offsets by calling this function. - * - * @param offset additional offset caused by preceding (variable length) instructions - * @param max_offset the maximum offset that may be caused by these instructions - * @return additional offset caused by possible change of this instruction's length - */ - protected int updatePosition( final int offset, final int max_offset ) { - i_position += offset; - return 0; - } - - - /** @return the position, i.e., the byte code offset of the contained - * instruction. This is accurate only after - * InstructionList.setPositions() has been called. - */ - public int getPosition() { - return i_position; - } - - - /** Set the position, i.e., the byte code offset of the contained - * instruction. - */ - void setPosition( final int pos ) { - i_position = pos; - } - - - /** - * Delete contents, i.e., remove user access. - */ - void dispose() { - next = prev = null; - instruction.dispose(); - instruction = null; - i_position = -1; - attributes = null; - removeAllTargeters(); - } - - - /** Remove all targeters, if any. - */ - public void removeAllTargeters() { - if (targeters != null) { - targeters.clear(); - } - } - - - /** - * Denote this handle isn't referenced anymore by t. - */ - public void removeTargeter( final InstructionTargeter t ) { - if (targeters != null) { - targeters.remove(t); - } - } - - - /** - * Denote this handle is being referenced by t. - */ - public void addTargeter( final InstructionTargeter t ) { - if (targeters == null) { - targeters = new HashSet<>(); - } - //if(!targeters.contains(t)) - targeters.add(t); - } - - - public boolean hasTargeters() { - return targeters != null && !targeters.isEmpty(); - } - - - /** - * @return null, if there are no targeters - */ - public InstructionTargeter[] getTargeters() { - if (!hasTargeters()) { - return EMPTY_INSTRUCTION_TARGETER_ARRAY; - } - final InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; - targeters.toArray(t); - return t; - } - - - /** @return a (verbose) string representation of the contained instruction. - */ - public String toString( final boolean verbose ) { - return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); - } - - - /** @return a string representation of the contained instruction. - */ - @Override - public String toString() { - return toString(true); - } - - - /** Add an attribute to an instruction handle. - * - * @param key the key object to store/retrieve the attribute - * @param attr the attribute to associate with this handle - */ - public void addAttribute( final Object key, final Object attr ) { - if (attributes == null) { - attributes = new HashMap<>(3); - } - attributes.put(key, attr); - } - - - /** Delete an attribute of an instruction handle. - * - * @param key the key object to retrieve the attribute - */ - public void removeAttribute( final Object key ) { - if (attributes != null) { - attributes.remove(key); - } - } - - - /** Get attribute of an instruction handle. - * - * @param key the key object to store/retrieve the attribute - */ - public Object getAttribute( final Object key ) { - if (attributes != null) { - return attributes.get(key); - } - return null; - } - - - /** @return all attributes associated with this handle - */ - public Collection<Object> getAttributes() { - if (attributes == null) { - attributes = new HashMap<>(3); - } - return attributes.values(); - } - - - /** Convenience method, simply calls accept() on the contained instruction. - * - * @param v Visitor object - */ - public void accept( final Visitor v ) { - instruction.accept(v); - } - - - /** - * @param next the next to set - * @since 6.0 - */ - final InstructionHandle setNext(final InstructionHandle next) { - this.next = next; - return next; - } - - - /** - * @param prev the prev to set - * @since 6.0 - */ - final InstructionHandle setPrev(final InstructionHandle prev) { - this.prev = prev; - return prev; - } -} +/* + * 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.generic; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.bcel.classfile.Utility; + +/** + * Instances of this class give users a handle to the instructions contained in + * an InstructionList. Instruction objects may be used more than once within a + * list, this is useful because it saves memory and may be much faster. + * + * Within an InstructionList an InstructionHandle object is wrapped + * around all instructions, i.e., it implements a cell in a + * doubly-linked list. From the outside only the next and the + * previous instruction (handle) are accessible. One + * can traverse the list via an Enumeration returned by + * InstructionList.elements(). + * + * @see Instruction + * @see BranchHandle + * @see InstructionList + */ +public class InstructionHandle { + + /** + * Empty array. + * + * @since 6.6.0 + */ + public static final InstructionHandle[] EMPTY_INSTRUCTION_HANDLE_ARRAY = new InstructionHandle[0]; + + /** + * Empty array. + */ + static final InstructionTargeter[] EMPTY_INSTRUCTION_TARGETER_ARRAY = new InstructionTargeter[0]; + + private InstructionHandle next; + private InstructionHandle prev; + private Instruction instruction; + + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected int i_position = -1; // byte code offset of instruction + + private Set<InstructionTargeter> targeters; + private Map<Object, Object> attributes; + + + /** + * Does nothing. + * + * @deprecated Does nothing as of 6.3.1. + */ + @Deprecated + protected void addHandle() { + // noop + } + + public final InstructionHandle getNext() { + return next; + } + + + public final InstructionHandle getPrev() { + return prev; + } + + + public final Instruction getInstruction() { + return instruction; + } + + + /** + * Replace current instruction contained in this handle. + * Old instruction is disposed using Instruction.dispose(). + */ + public void setInstruction( final Instruction i ) { // Overridden in BranchHandle TODO could be package-protected? + if (i == null) { + throw new ClassGenException("Assigning null to handle"); + } + if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) { + throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); + } + if (instruction != null) { + instruction.dispose(); + } + instruction = i; + } + + + /** + * Temporarily swap the current instruction, without disturbing + * anything. Meant to be used by a debugger, implementing + * breakpoints. Current instruction is returned. + * <p> + * Warning: if this is used on a BranchHandle then some methods such as + * getPosition() will still refer to the original cached instruction, whereas + * other BH methods may affect the cache and the replacement instruction. + */ + // See BCEL-273 + // TODO remove this method in any redesign of BCEL + public Instruction swapInstruction( final Instruction i ) { + final Instruction oldInstruction = instruction; + instruction = i; + return oldInstruction; + } + + + /*private*/protected InstructionHandle(final Instruction i) { + setInstruction(i); + } + + /** Factory method. + */ + static InstructionHandle getInstructionHandle( final Instruction i ) { + return new InstructionHandle(i); + } + + + /** + * Called by InstructionList.setPositions when setting the position for every + * instruction. In the presence of variable length instructions `setPositions()' + * performs multiple passes over the instruction list to calculate the + * correct (byte) positions and offsets by calling this function. + * + * @param offset additional offset caused by preceding (variable length) instructions + * @param max_offset the maximum offset that may be caused by these instructions + * @return additional offset caused by possible change of this instruction's length + */ + protected int updatePosition( final int offset, final int max_offset ) { + i_position += offset; + return 0; + } + + + /** @return the position, i.e., the byte code offset of the contained + * instruction. This is accurate only after + * InstructionList.setPositions() has been called. + */ + public int getPosition() { + return i_position; + } + + + /** Set the position, i.e., the byte code offset of the contained + * instruction. + */ + void setPosition( final int pos ) { + i_position = pos; + } + + + /** + * Delete contents, i.e., remove user access. + */ + void dispose() { + next = prev = null; + instruction.dispose(); + instruction = null; + i_position = -1; + attributes = null; + removeAllTargeters(); + } + + + /** Remove all targeters, if any. + */ + public void removeAllTargeters() { + if (targeters != null) { + targeters.clear(); + } + } + + + /** + * Denote this handle isn't referenced anymore by t. + */ + public void removeTargeter( final InstructionTargeter t ) { + if (targeters != null) { + targeters.remove(t); + } + } + + + /** + * Denote this handle is being referenced by t. + */ + public void addTargeter( final InstructionTargeter t ) { + if (targeters == null) { + targeters = new HashSet<>(); + } + //if(!targeters.contains(t)) + targeters.add(t); + } + + + public boolean hasTargeters() { + return targeters != null && !targeters.isEmpty(); + } + + + /** + * @return null, if there are no targeters + */ + public InstructionTargeter[] getTargeters() { + if (!hasTargeters()) { + return EMPTY_INSTRUCTION_TARGETER_ARRAY; + } + final InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; + targeters.toArray(t); + return t; + } + + + /** @return a (verbose) string representation of the contained instruction. + */ + public String toString( final boolean verbose ) { + return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); + } + + + /** @return a string representation of the contained instruction. + */ + @Override + public String toString() { + return toString(true); + } + + + /** Add an attribute to an instruction handle. + * + * @param key the key object to store/retrieve the attribute + * @param attr the attribute to associate with this handle + */ + public void addAttribute( final Object key, final Object attr ) { + if (attributes == null) { + attributes = new HashMap<>(3); + } + attributes.put(key, attr); + } + + + /** Delete an attribute of an instruction handle. + * + * @param key the key object to retrieve the attribute + */ + public void removeAttribute( final Object key ) { + if (attributes != null) { + attributes.remove(key); + } + } + + + /** Get attribute of an instruction handle. + * + * @param key the key object to store/retrieve the attribute + */ + public Object getAttribute( final Object key ) { + if (attributes != null) { + return attributes.get(key); + } + return null; + } + + + /** @return all attributes associated with this handle + */ + public Collection<Object> getAttributes() { + if (attributes == null) { + attributes = new HashMap<>(3); + } + return attributes.values(); + } + + + /** Convenience method, simply calls accept() on the contained instruction. + * + * @param v Visitor object + */ + public void accept( final Visitor v ) { + instruction.accept(v); + } + + + /** + * @param next the next to set + * @since 6.0 + */ + final InstructionHandle setNext(final InstructionHandle next) { + this.next = next; + return next; + } + + + /** + * @param prev the prev to set + * @since 6.0 + */ + final InstructionHandle setPrev(final InstructionHandle prev) { + this.prev = prev; + return prev; + } +} diff --git a/src/main/java/org/apache/bcel/util/ModularRuntimeImage.java b/src/main/java/org/apache/bcel/util/ModularRuntimeImage.java index 1c80deea..64d698e5 100644 --- a/src/main/java/org/apache/bcel/util/ModularRuntimeImage.java +++ b/src/main/java/org/apache/bcel/util/ModularRuntimeImage.java @@ -1,152 +1,152 @@ -/* - * 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.util; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Wraps a Java 9 JEP 220 modular runtime image. Requires the JRT NIO file system. - * - * @since 6.3 - */ -public class ModularRuntimeImage implements Closeable { - - static final String MODULES_PATH = File.separator + "modules"; - static final String PACKAGES_PATH = File.separator + "packages"; - - private final URLClassLoader classLoader; - private final FileSystem fileSystem; - - /** - * Constructs a default instance. - * - * @throws IOException - * an I/O error occurs accessing the file system - */ - public ModularRuntimeImage() throws IOException { - this(null, FileSystems.getFileSystem(URI.create("jrt:/"))); - } - - /** - * Constructs an instance using the JRT file system implementation from a specific Java Home. - * - * @param javaHome - * Path to a Java 9 or greater home. - * - * @throws IOException - * an I/O error occurs accessing the file system - */ - public ModularRuntimeImage(final String javaHome) throws IOException { - final Map<String, ?> emptyMap = Collections.emptyMap(); - final Path jrePath = Paths.get(javaHome); - final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar"); - this.classLoader = new URLClassLoader(new URL[] {jrtFsPath.toUri().toURL() }); - this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader); - } - - private ModularRuntimeImage(final URLClassLoader cl, final FileSystem fs) { - this.classLoader = cl; - this.fileSystem = fs; - } - - @Override - public void close() throws IOException { - if (classLoader != null) { - classLoader.close(); - } - if (fileSystem != null) { - fileSystem.close(); - } - } - - /** - * Lists all entries in the given directory. - * - * @param dirPath - * directory path. - * @return a list of dir entries if an I/O error occurs - * @throws IOException - * an I/O error occurs accessing the file system - */ - public List<Path> list(final Path dirPath) throws IOException { - final List<Path> list = new ArrayList<>(); - try (DirectoryStream<Path> ds = Files.newDirectoryStream(dirPath)) { - final Iterator<Path> iterator = ds.iterator(); - while (iterator.hasNext()) { - list.add(iterator.next()); - } - } - return list; - } - - /** - * Lists all entries in the given directory. - * - * @param dirName - * directory path. - * @return a list of dir entries if an I/O error occurs - * @throws IOException - * an I/O error occurs accessing the file system - */ - public List<Path> list(final String dirName) throws IOException { - return list(fileSystem.getPath(dirName)); - } - - /** - * Lists all modules. - * - * @return a list of modules - * @throws IOException - * an I/O error occurs accessing the file system - */ - public List<Path> modules() throws IOException { - return list(MODULES_PATH); - } - - /** - * Lists all packages. - * - * @return a list of modules - * @throws IOException - * an I/O error occurs accessing the file system - */ - public List<Path> packages() throws IOException { - return list(PACKAGES_PATH); - } - - public FileSystem getFileSystem() { - return fileSystem; - } - -} +/* + * 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.util; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Wraps a Java 9 JEP 220 modular runtime image. Requires the JRT NIO file system. + * + * @since 6.3 + */ +public class ModularRuntimeImage implements Closeable { + + static final String MODULES_PATH = File.separator + "modules"; + static final String PACKAGES_PATH = File.separator + "packages"; + + private final URLClassLoader classLoader; + private final FileSystem fileSystem; + + /** + * Constructs a default instance. + * + * @throws IOException + * an I/O error occurs accessing the file system + */ + public ModularRuntimeImage() throws IOException { + this(null, FileSystems.getFileSystem(URI.create("jrt:/"))); + } + + /** + * Constructs an instance using the JRT file system implementation from a specific Java Home. + * + * @param javaHome + * Path to a Java 9 or greater home. + * + * @throws IOException + * an I/O error occurs accessing the file system + */ + public ModularRuntimeImage(final String javaHome) throws IOException { + final Map<String, ?> emptyMap = Collections.emptyMap(); + final Path jrePath = Paths.get(javaHome); + final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar"); + this.classLoader = new URLClassLoader(new URL[] {jrtFsPath.toUri().toURL() }); + this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader); + } + + private ModularRuntimeImage(final URLClassLoader cl, final FileSystem fs) { + this.classLoader = cl; + this.fileSystem = fs; + } + + @Override + public void close() throws IOException { + if (classLoader != null) { + classLoader.close(); + } + if (fileSystem != null) { + fileSystem.close(); + } + } + + /** + * Lists all entries in the given directory. + * + * @param dirPath + * directory path. + * @return a list of dir entries if an I/O error occurs + * @throws IOException + * an I/O error occurs accessing the file system + */ + public List<Path> list(final Path dirPath) throws IOException { + final List<Path> list = new ArrayList<>(); + try (DirectoryStream<Path> ds = Files.newDirectoryStream(dirPath)) { + final Iterator<Path> iterator = ds.iterator(); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + } + return list; + } + + /** + * Lists all entries in the given directory. + * + * @param dirName + * directory path. + * @return a list of dir entries if an I/O error occurs + * @throws IOException + * an I/O error occurs accessing the file system + */ + public List<Path> list(final String dirName) throws IOException { + return list(fileSystem.getPath(dirName)); + } + + /** + * Lists all modules. + * + * @return a list of modules + * @throws IOException + * an I/O error occurs accessing the file system + */ + public List<Path> modules() throws IOException { + return list(MODULES_PATH); + } + + /** + * Lists all packages. + * + * @return a list of modules + * @throws IOException + * an I/O error occurs accessing the file system + */ + public List<Path> packages() throws IOException { + return list(PACKAGES_PATH); + } + + public FileSystem getFileSystem() { + return fileSystem; + } + +}