jdk/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java
2025-01-27 14:03:35 +00:00

162 lines
7.8 KiB
Java

/*
* Copyright (c) 2022, 2025, 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 java.lang.classfile;
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* A transformation on a {@link CompoundElement} by processing its individual
* member elements and sending the results to a {@link ClassFileBuilder},
* through {@link ClassFileBuilder#transform}. A subtype of {@code
* ClassFileTransform} is defined for each subtype of {@link CompoundElement}
* and {@link ClassFileBuilder}, as shown in the sealed class hierarchy below.
* <p>
* For example, this is a basic transformation of a {@link CodeModel} that
* redirects all calls to static methods in the {@code Foo} class to the {@code
* Bar} class, preserving all other elements:
* {@snippet file="PackageSnippets.java" region=fooToBarTransform}
* Note that if no transformation of a member element is desired, the element
* should be presented to {@link ClassFileBuilder#with builder::with}. If no
* action is taken, that member element is dropped.
* <p>
* More advanced usages of transforms include {@linkplain ##start-end start or
* end handling}, {@linkplain ##stateful stateful transformation} that makes a
* decision based on previously encountered member elements, and {@linkplain
* ##composition composition} of transforms, where one transform processes the
* results of a previous transform on the input compound structure. All these
* capabilities are supported by this interface and accessible to user transform
* implementations.
* <p id="start-end">
* Users can define custom start and end handling for a transform by overriding
* {@link #atStart} and {@link #atEnd}. The start handler is called before any
* member element is processed, and the end handler is called after all member
* elements are processed. For example, the start handler can be used to inject
* extra code elements to the beginning of a code array, and the end handler,
* combined with stateful transformation, can perform cleanup actions, such as
* determining if an attribute has been merged, or if a new attribute should be
* defined. Each subtype of {@code ClassFileTransform} defines a utility method
* {@code endHandler} that returns a transform that only has end handling.
* <p id="stateful">
* Transforms can have states that persist across processing of individual
* member elements. For example, if a transform injects an annotation, the
* transform may keep track if it has encountered and presented an updated
* {@link RuntimeVisibleAnnotationsAttribute} to the builder; if it has not yet,
* it can present a new attribute containing only the injected annotation in its
* end handler. If such a transform is to be shared or reused, each returned
* transform should have its own state. Each subtype of {@code ClassFileTransform}
* defines a utility method {@code ofStateful} where a supplier creates the
* transform at its initial state each time the transform is reused.
* <p id="composition">
* Transforms can be composed via {@link #andThen}. When this transform is
* composed with another transform, it means the output member elements received
* by the {@link ClassFileBuilder} become the input elements to that other
* transform. Composition avoids building intermediate structures for multiple
* transforms to run on. Each subtype of {@code ClassFileTransform} implements
* {@link #andThen}, which generally should not be implemented by users.
* <p>
* Transforms that run on smaller structures can be lifted to its enclosing
* structures to selectively run on all enclosed smaller structures of the same
* kind. For example, a {@link CodeTransform} can be lifted via {@link
* ClassTransform#transformingMethodBodies(Predicate, CodeTransform)} to
* transform the method body of select methods in the class it runs on. This
* allows users to write small transforms and apply to larger scales.
* <p>
* Besides {@link ClassFileBuilder#transform}, there are other methods that
* accepts a transform conveniently, such as {@link ClassFile#transformClass},
* {@link ClassBuilder#transformField}, {@link ClassBuilder#transformMethod}, or
* {@link MethodBuilder#transformCode}. They are convenience methods that suit
* the majority of transformation scenarios.
*
* @param <C> the transform type
* @param <E> the member element type
* @param <B> the builder type
*
* @sealedGraph
* @since 24
*/
public sealed interface ClassFileTransform<
C extends ClassFileTransform<C, E, B>,
E extends ClassFileElement,
B extends ClassFileBuilder<E, B>>
permits ClassTransform, FieldTransform, MethodTransform, CodeTransform {
/**
* Transform an element by taking the appropriate actions on the builder.
* Used when transforming a classfile entity (class, method, field, method
* body.) If no transformation is desired, the element can be presented to
* {@link B#with(ClassFileElement)}. If the element is to be dropped, no
* action is required.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @param element the element
*/
void accept(B builder, E element);
/**
* Take any final action during transformation of a classfile entity. Called
* after all elements of the class are presented to {@link
* #accept(ClassFileBuilder, ClassFileElement)}.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @implSpec The default implementation does nothing.
*/
default void atEnd(B builder) {
}
/**
* Take any preliminary action during transformation of a classfile entity.
* Called before any elements of the class are presented to {@link
* #accept(ClassFileBuilder, ClassFileElement)}.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @implSpec The default implementation does nothing.
*/
default void atStart(B builder) {
}
/**
* Chain this transform with another; elements presented to the builder of
* this transform will become the input to the next transform.
* <p>
* This method is implemented by the Class-File API. Users usually don't
* have sufficient access to Class-File API functionalities to override this
* method correctly for generic downstream transforms.
*
* @param next the downstream transform
* @return the chained transform
*/
C andThen(C next);
}