io.github.dmlloyd.classfile.impl.TransformImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdk-classfile-backport Show documentation
Show all versions of jdk-classfile-backport Show documentation
An unofficial backport of the JDK Classfile API to Java 17
/*
* Copyright (c) 2022, 2024, 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.impl;
import io.github.dmlloyd.classfile.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
public final class TransformImpl {
// ClassTransform
private TransformImpl() {
}
private static Runnable chainRunnable(Runnable a, Runnable b) {
return () -> { a.run(); b.run(); };
}
private static final Runnable NOTHING = () -> { };
public static >
ResolvedTransform resolve(ClassFileTransform, E, B> transform, B builder) {
if (transform instanceof ResolvableTransform) {
@SuppressWarnings("unchecked")
var ut = (ResolvableTransform) transform;
return ut.resolve(builder);
}
return new ResolvedTransform<>(e -> transform.accept(builder, e),
() -> transform.atEnd(builder),
() -> transform.atStart(builder));
}
interface ResolvableTransform> {
ResolvedTransform resolve(B builder);
}
interface UnresolvedClassTransform extends ClassTransform, ResolvableTransform {
@Override
default void accept(ClassBuilder builder, ClassElement element) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atEnd(ClassBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atStart(ClassBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
}
public record ResolvedTransform(Consumer consumer,
Runnable endHandler,
Runnable startHandler) {
public ResolvedTransform(Consumer consumer) {
this(consumer, NOTHING, NOTHING);
}
}
public record ChainedClassTransform(ClassTransform t,
ClassTransform next)
implements UnresolvedClassTransform {
@Override
public ResolvedTransform resolve(ClassBuilder builder) {
ResolvedTransform downstream = TransformImpl.resolve(next, builder);
ClassBuilder chainedBuilder = new ChainedClassBuilder(builder, downstream.consumer());
ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder);
return new ResolvedTransform<>(upstream.consumer(),
chainRunnable(upstream.endHandler(), downstream.endHandler()),
chainRunnable(downstream.startHandler(), upstream.startHandler()));
}
}
public record SupplierClassTransform(Supplier supplier)
implements UnresolvedClassTransform {
@Override
public ResolvedTransform resolve(ClassBuilder builder) {
return TransformImpl.resolve(supplier.get(), builder);
}
}
public record ClassMethodTransform(MethodTransform transform,
Predicate filter)
implements UnresolvedClassTransform {
@Override
public ResolvedTransform resolve(ClassBuilder builder) {
return new ResolvedTransform<>(ce -> {
if (ce instanceof MethodModel mm && filter.test(mm))
builder.transformMethod(mm, transform);
else
builder.with(ce);
});
}
@Override
public ClassTransform andThen(ClassTransform next) {
if (next instanceof ClassMethodTransform cmt)
return new ClassMethodTransform(transform.andThen(cmt.transform),
mm -> filter.test(mm) && cmt.filter.test(mm));
else
return UnresolvedClassTransform.super.andThen(next);
}
}
public record ClassFieldTransform(FieldTransform transform,
Predicate filter)
implements UnresolvedClassTransform {
@Override
public ResolvedTransform resolve(ClassBuilder builder) {
return new ResolvedTransform<>(ce -> {
if (ce instanceof FieldModel fm && filter.test(fm))
builder.transformField(fm, transform);
else
builder.with(ce);
});
}
@Override
public ClassTransform andThen(ClassTransform next) {
if (next instanceof ClassFieldTransform cft)
return new ClassFieldTransform(transform.andThen(cft.transform),
mm -> filter.test(mm) && cft.filter.test(mm));
else
return UnresolvedClassTransform.super.andThen(next);
}
}
// MethodTransform
interface UnresolvedMethodTransform extends MethodTransform, ResolvableTransform {
@Override
default void accept(MethodBuilder builder, MethodElement element) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atEnd(MethodBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atStart(MethodBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
}
public record ChainedMethodTransform(MethodTransform t,
MethodTransform next)
implements TransformImpl.UnresolvedMethodTransform {
@Override
public ResolvedTransform resolve(MethodBuilder builder) {
ResolvedTransform downstream = TransformImpl.resolve(next, builder);
MethodBuilder chainedBuilder = new ChainedMethodBuilder(builder, downstream.consumer());
ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder);
return new ResolvedTransform<>(upstream.consumer(),
chainRunnable(upstream.endHandler(), downstream.endHandler()),
chainRunnable(downstream.startHandler(), upstream.startHandler()));
}
}
public record SupplierMethodTransform(Supplier supplier)
implements TransformImpl.UnresolvedMethodTransform {
@Override
public ResolvedTransform resolve(MethodBuilder builder) {
return TransformImpl.resolve(supplier.get(), builder);
}
}
public record MethodCodeTransform(CodeTransform xform)
implements TransformImpl.UnresolvedMethodTransform {
@Override
public ResolvedTransform resolve(MethodBuilder builder) {
return new ResolvedTransform<>(me -> {
if (me instanceof CodeModel cm) {
builder.transformCode(cm, xform);
}
else {
builder.with(me);
}
}, NOTHING, NOTHING);
}
@Override
public MethodTransform andThen(MethodTransform next) {
return (next instanceof MethodCodeTransform mct)
? new MethodCodeTransform(xform.andThen(mct.xform))
: UnresolvedMethodTransform.super.andThen(next);
}
}
// FieldTransform
interface UnresolvedFieldTransform extends FieldTransform, ResolvableTransform {
@Override
default void accept(FieldBuilder builder, FieldElement element) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atEnd(FieldBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atStart(FieldBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
}
public record ChainedFieldTransform(FieldTransform t, FieldTransform next)
implements UnresolvedFieldTransform {
@Override
public ResolvedTransform resolve(FieldBuilder builder) {
ResolvedTransform downstream = TransformImpl.resolve(next, builder);
FieldBuilder chainedBuilder = new ChainedFieldBuilder(builder, downstream.consumer());
ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder);
return new ResolvedTransform<>(upstream.consumer(),
chainRunnable(upstream.endHandler(), downstream.endHandler()),
chainRunnable(downstream.startHandler(), upstream.startHandler()));
}
}
public record SupplierFieldTransform(Supplier supplier)
implements UnresolvedFieldTransform {
@Override
public ResolvedTransform resolve(FieldBuilder builder) {
return TransformImpl.resolve(supplier.get(), builder);
}
}
// CodeTransform
interface UnresolvedCodeTransform extends CodeTransform, ResolvableTransform {
@Override
default void accept(CodeBuilder builder, CodeElement element) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atEnd(CodeBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
@Override
default void atStart(CodeBuilder builder) {
throw new UnsupportedOperationException("transforms must be resolved before running");
}
}
public record ChainedCodeTransform(CodeTransform t, CodeTransform next)
implements UnresolvedCodeTransform {
@Override
public ResolvedTransform resolve(CodeBuilder builder) {
ResolvedTransform downstream = TransformImpl.resolve(next, builder);
CodeBuilder chainedBuilder = new ChainedCodeBuilder(builder, downstream.consumer());
ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder);
return new ResolvedTransform<>(upstream.consumer(),
chainRunnable(upstream.endHandler(), downstream.endHandler()),
chainRunnable(downstream.startHandler(), upstream.startHandler()));
}
}
public record SupplierCodeTransform(Supplier supplier)
implements UnresolvedCodeTransform {
@Override
public ResolvedTransform resolve(CodeBuilder builder) {
return TransformImpl.resolve(supplier.get(), builder);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy