io.github.dmlloyd.classfile.components.ClassPrinter Maven / Gradle / Ivy
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package io.github.dmlloyd.classfile.components;
import java.lang.constant.ConstantDesc;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
import io.github.dmlloyd.classfile.ClassModel;
import io.github.dmlloyd.classfile.FieldModel;
import io.github.dmlloyd.classfile.MethodModel;
import io.github.dmlloyd.classfile.CodeModel;
import io.github.dmlloyd.classfile.CompoundElement;
import io.github.dmlloyd.classfile.impl.ClassPrinterImpl;
import io.github.dmlloyd.classfile.extras.PreviewFeature;
/**
* A printer of classfiles and its elements.
*
* Any {@link ClassModel}, {@link FieldModel}, {@link MethodModel}, or {@link CodeModel}
* can be printed to a human-readable structured text in JSON, XML, or YAML format.
* Or it can be exported into a tree of traversable and printable nodes,
* more exactly into a tree of {@link MapNode}, {@link ListNode}, and {@link LeafNode} instances.
*
* Level of details to print or to export is driven by {@link Verbosity} option.
*
* Printing is for debugging purposes only. Printed text schema, tree content and structure
* not guaranteed. It may change anytime in a future.
*
* The most frequent use case is to simply print a class:
* {@snippet lang="java" class="PackageSnippets" region="printClass"}
*
* {@link ClassPrinter} allows to traverse tree of simple printable nodes to hook custom printer:
* {@snippet lang="java" class="PackageSnippets" region="customPrint"}
*
* Another use case for {@link ClassPrinter} is to simplify writing of automated tests:
* {@snippet lang="java" class="PackageSnippets" region="printNodesInTest"}
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public final class ClassPrinter {
private ClassPrinter() {
}
/**
* Level of detail to print or export.
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public enum Verbosity {
/**
* Only top level class info, class members and attribute names are printed.
*/
MEMBERS_ONLY,
/**
* Top level class info, class members, and critical attributes are printed.
*
* Critical attributes are:
*
* - ConstantValue
*
- Code
*
- StackMapTable
*
- BootstrapMethods
*
- NestHost
*
- NestMembers
*
- PermittedSubclasses
*
* @jvms 4.7 Attributes
*/
CRITICAL_ATTRIBUTES,
/**
* All class content is printed, including constant pool.
*/
TRACE_ALL }
/**
* Named, traversable, and printable node parent.
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface Node {
/**
* Printable name of the node.
* @return name of the node
*/
ConstantDesc name();
/**
* Walks through the underlying tree.
* @return ordered stream of nodes
*/
Stream walk();
/**
* Prints the node and its sub-tree into JSON format.
* @param out consumer of the printed fragments
*/
default void toJson(Consumer out) {
ClassPrinterImpl.toJson(this, out);
}
/**
* Prints the node and its sub-tree into XML format.
* @param out consumer of the printed fragments
*/
default void toXml(Consumer out) {
ClassPrinterImpl.toXml(this, out);
}
/**
* Prints the node and its sub-tree into YAML format.
* @param out consumer of the printed fragments
*/
default void toYaml(Consumer out) {
ClassPrinterImpl.toYaml(this, out);
}
}
/**
* A leaf node holding single printable value.
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface LeafNode extends Node
permits ClassPrinterImpl.LeafNodeImpl {
/**
* Printable node value
* @return node value
*/
ConstantDesc value();
}
/**
* A tree node holding {@link List} of nested nodes.
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface ListNode extends Node, List
permits ClassPrinterImpl.ListNodeImpl {
}
/**
* A tree node holding {@link Map} of nested nodes.
*
* Each {@link Map.Entry#getKey()} == {@link Map.Entry#getValue()}.{@link #name()}.
*
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface MapNode extends Node, Map
permits ClassPrinterImpl.MapNodeImpl {
}
/**
* Exports provided model into a tree of printable nodes.
* @param model a {@link ClassModel}, {@link FieldModel}, {@link MethodModel}, or {@link CodeModel} to export
* @param verbosity level of details to export
* @return root node of the exported tree
*/
public static MapNode toTree(CompoundElement> model, Verbosity verbosity) {
return ClassPrinterImpl.modelToTree(model, verbosity);
}
/**
* Prints provided model as structured text in JSON format.
* @param model a {@link ClassModel}, {@link FieldModel}, {@link MethodModel}, or {@link CodeModel} to print
* @param verbosity level of details to print
* @param out consumer of the print fragments
*/
public static void toJson(CompoundElement> model, Verbosity verbosity, Consumer out) {
toTree(model, verbosity).toJson(out);
}
/**
* Prints provided model as structured text in XML format.
* @param model a {@link ClassModel}, {@link FieldModel}, {@link MethodModel}, or {@link CodeModel} to print
* @param verbosity level of details to print
* @param out consumer of the print fragments
*/
public static void toXml(CompoundElement> model, Verbosity verbosity, Consumer out) {
toTree(model, verbosity).toXml(out);
}
/**
* Prints provided model as structured text in YAML format.
* @param model a {@link ClassModel}, {@link FieldModel}, {@link MethodModel}, or {@link CodeModel} to print
* @param verbosity level of details to print
* @param out consumer of the print fragments
*/
public static void toYaml(CompoundElement> model, Verbosity verbosity, Consumer out) {
toTree(model, verbosity).toYaml(out);
}
}