/*
 * Copyright 2014 - 2020 Rafael Winterhalter
 *
 * Licensed 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 net.bytebuddy.implementation;

import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.implementation.bytecode.*;
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
import org.objectweb.asm.MethodVisitor;

import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

This implementation causes a Throwable to be thrown when the instrumented method is invoked. Be aware that the Java Virtual machine does not care about exception declarations and will throw any Throwable from any method even if the method does not declared a checked exception.
/** * This implementation causes a {@link java.lang.Throwable} to be thrown when the instrumented method is invoked. * Be aware that the Java Virtual machine does not care about exception declarations and will throw any * {@link java.lang.Throwable} from any method even if the method does not declared a checked exception. */
@HashCodeAndEqualsPlugin.Enhance public class ExceptionMethod implements Implementation, ByteCodeAppender {
The construction delegation which is responsible for creating the exception to be thrown.
/** * The construction delegation which is responsible for creating the exception to be thrown. */
private final ConstructionDelegate constructionDelegate;
Creates a new instance of an implementation for throwing throwables.
Params:
  • constructionDelegate – A delegate that is responsible for calling the Throwable's constructor.
/** * Creates a new instance of an implementation for throwing throwables. * * @param constructionDelegate A delegate that is responsible for calling the {@link Throwable}'s constructor. */
public ExceptionMethod(ConstructionDelegate constructionDelegate) { this.constructionDelegate = constructionDelegate; }
Creates an implementation that creates a new instance of the given Throwable type on each method invocation which is then thrown immediately. For this to be possible, the given type must define a default constructor which is visible from the instrumented type.
Params:
Returns:An implementation that will throw an instance of the Throwable on each method invocation of the instrumented methods.
/** * Creates an implementation that creates a new instance of the given {@link Throwable} type on each method invocation * which is then thrown immediately. For this to be possible, the given type must define a default constructor * which is visible from the instrumented type. * * @param throwableType The type of the {@link Throwable}. * @return An implementation that will throw an instance of the {@link Throwable} on each method invocation of the * instrumented methods. */
public static Implementation throwing(Class<? extends Throwable> throwableType) { return throwing(TypeDescription.ForLoadedType.of(throwableType)); }
Creates an implementation that creates a new instance of the given Throwable type on each method invocation which is then thrown immediately. For this to be possible, the given type must define a default constructor which is visible from the instrumented type.
Params:
Returns:An implementation that will throw an instance of the Throwable on each method invocation of the instrumented methods.
/** * Creates an implementation that creates a new instance of the given {@link Throwable} type on each method invocation * which is then thrown immediately. For this to be possible, the given type must define a default constructor * which is visible from the instrumented type. * * @param throwableType The type of the {@link Throwable}. * @return An implementation that will throw an instance of the {@link Throwable} on each method invocation of the * instrumented methods. */
public static Implementation throwing(TypeDescription throwableType) { if (!throwableType.isAssignableTo(Throwable.class)) { throw new IllegalArgumentException(throwableType + " does not extend throwable"); } return new ExceptionMethod(new ConstructionDelegate.ForDefaultConstructor(throwableType)); }
Creates an implementation that creates a new instance of the given Throwable type on each method invocation which is then thrown immediately. For this to be possible, the given type must define a constructor that takes a single String as its argument.
Params:
  • throwableType – The type of the Throwable.
  • message – The string that is handed to the constructor. Usually an exception message.
Returns:An implementation that will throw an instance of the Throwable on each method invocation of the instrumented methods.
/** * Creates an implementation that creates a new instance of the given {@link Throwable} type on each method * invocation which is then thrown immediately. For this to be possible, the given type must define a * constructor that takes a single {@link java.lang.String} as its argument. * * @param throwableType The type of the {@link Throwable}. * @param message The string that is handed to the constructor. Usually an exception message. * @return An implementation that will throw an instance of the {@link Throwable} on each method invocation * of the instrumented methods. */
public static Implementation throwing(Class<? extends Throwable> throwableType, String message) { return throwing(TypeDescription.ForLoadedType.of(throwableType), message); }
Creates an implementation that creates a new instance of the given Throwable type on each method invocation which is then thrown immediately. For this to be possible, the given type must define a constructor that takes a single String as its argument.
Params:
  • throwableType – The type of the Throwable.
  • message – The string that is handed to the constructor. Usually an exception message.
Returns:An implementation that will throw an instance of the Throwable on each method invocation of the instrumented methods.
/** * Creates an implementation that creates a new instance of the given {@link Throwable} type on each method * invocation which is then thrown immediately. For this to be possible, the given type must define a * constructor that takes a single {@link java.lang.String} as its argument. * * @param throwableType The type of the {@link Throwable}. * @param message The string that is handed to the constructor. Usually an exception message. * @return An implementation that will throw an instance of the {@link Throwable} on each method invocation * of the instrumented methods. */
public static Implementation throwing(TypeDescription throwableType, String message) { if (!throwableType.isAssignableTo(Throwable.class)) { throw new IllegalArgumentException(throwableType + " does not extend throwable"); } return new ExceptionMethod(new ConstructionDelegate.ForStringConstructor(throwableType, message)); }
{@inheritDoc}
/** * {@inheritDoc} */
public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType; }
{@inheritDoc}
/** * {@inheritDoc} */
public ByteCodeAppender appender(Target implementationTarget) { return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { StackManipulation.Size stackSize = new StackManipulation.Compound( constructionDelegate.make(), Throw.INSTANCE ).apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); }
A construction delegate is responsible for calling a Throwable's constructor.
/** * A construction delegate is responsible for calling a {@link Throwable}'s constructor. */
public interface ConstructionDelegate {
Creates a stack manipulation that creates pushes all constructor arguments onto the operand stack and subsequently calls the constructor.
Returns:A stack manipulation for constructing a Throwable.
/** * Creates a stack manipulation that creates pushes all constructor arguments onto the operand stack * and subsequently calls the constructor. * * @return A stack manipulation for constructing a {@link Throwable}. */
StackManipulation make();
A construction delegate that calls the default constructor.
/** * A construction delegate that calls the default constructor. */
@HashCodeAndEqualsPlugin.Enhance class ForDefaultConstructor implements ConstructionDelegate {
The type of the exception that is to be thrown.
/** * The type of the exception that is to be thrown. */
private final TypeDescription throwableType;
The constructor that is used for creating the exception.
/** * The constructor that is used for creating the exception. */
private final MethodDescription targetConstructor;
Creates a new construction delegate that calls a default constructor.
Params:
/** * Creates a new construction delegate that calls a default constructor. * * @param throwableType The type of the {@link Throwable}. */
public ForDefaultConstructor(TypeDescription throwableType) { this.throwableType = throwableType; this.targetConstructor = throwableType.getDeclaredMethods() .filter(isConstructor().and(takesArguments(0))).getOnly(); }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation make() { return new StackManipulation.Compound( TypeCreation.of(throwableType), Duplication.SINGLE, MethodInvocation.invoke(targetConstructor)); } }
A construction delegate that calls a constructor that takes a single string as its argument.
/** * A construction delegate that calls a constructor that takes a single string as its argument. */
@HashCodeAndEqualsPlugin.Enhance class ForStringConstructor implements ConstructionDelegate {
The type of the exception that is to be thrown.
/** * The type of the exception that is to be thrown. */
private final TypeDescription throwableType;
The constructor that is used for creating the exception.
/** * The constructor that is used for creating the exception. */
private final MethodDescription targetConstructor;
The String that is to be passed to the exception's constructor.
/** * The {@link java.lang.String} that is to be passed to the exception's constructor. */
private final String message;
Creates a new construction delegate that calls a constructor by handing it the given string.
Params:
  • throwableType – The type of the Throwable.
  • message – The string that is handed to the constructor.
/** * Creates a new construction delegate that calls a constructor by handing it the given string. * * @param throwableType The type of the {@link Throwable}. * @param message The string that is handed to the constructor. */
public ForStringConstructor(TypeDescription throwableType, String message) { this.throwableType = throwableType; this.targetConstructor = throwableType.getDeclaredMethods() .filter(isConstructor().and(takesArguments(String.class))).getOnly(); this.message = message; }
{@inheritDoc}
/** * {@inheritDoc} */
public StackManipulation make() { return new StackManipulation.Compound( TypeCreation.of(throwableType), Duplication.SINGLE, new TextConstant(message), MethodInvocation.invoke(targetConstructor)); } } } }