mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-29 12:38:24 +00:00
162 lines
7.8 KiB
Java
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);
|
|
}
|