-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Done homework 11 * Fixes homework 11 * Fix jacoco problem * Fix jacoco problem
- Loading branch information
1 parent
c995f60
commit 1cdd777
Showing
8 changed files
with
244 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package edu.hw11.task1; | ||
|
||
import net.bytebuddy.ByteBuddy; | ||
import net.bytebuddy.implementation.FixedValue; | ||
import net.bytebuddy.matcher.ElementMatchers; | ||
|
||
public final class HelloWorldCreator { | ||
|
||
private HelloWorldCreator() { | ||
} | ||
|
||
public static Object createHelloWorld() { | ||
try (var unloaded = new ByteBuddy() | ||
.subclass(Object.class) | ||
.method(ElementMatchers.isToString()) | ||
.intercept(FixedValue.value("Hello, ByteBuddy!")) | ||
.make() | ||
) { | ||
return unloaded.load(HelloWorldCreator.class.getClassLoader()).getLoaded().getConstructor().newInstance(); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package edu.hw11.task2; | ||
|
||
public final class ArithmeticUtils { | ||
private ArithmeticUtils() { | ||
} | ||
|
||
public static int sum(int a, int b) { | ||
return a + b; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package edu.hw11.task2; | ||
|
||
import net.bytebuddy.ByteBuddy; | ||
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; | ||
import net.bytebuddy.implementation.MethodDelegation; | ||
import net.bytebuddy.matcher.ElementMatchers; | ||
|
||
public final class ClassBehaviourReloader { | ||
|
||
private ClassBehaviourReloader() { | ||
} | ||
|
||
/** | ||
* Should be called after installing the agent {@link net.bytebuddy.agent.ByteBuddyAgent ByteBuddyAgent} | ||
*/ | ||
public static void reload() { | ||
new ByteBuddy() | ||
.redefine(ArithmeticUtils.class) | ||
.method(ElementMatchers.named("sum")) | ||
.intercept(MethodDelegation.to(Delegate.class)) | ||
.make() | ||
.load(ArithmeticUtils.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); | ||
} | ||
|
||
private final static class Delegate { | ||
public static int sum(int a, int b) { | ||
return a * b; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package edu.hw11.task3; | ||
|
||
import net.bytebuddy.ByteBuddy; | ||
import net.bytebuddy.description.method.MethodDescription; | ||
import net.bytebuddy.description.modifier.Ownership; | ||
import net.bytebuddy.description.modifier.Visibility; | ||
import net.bytebuddy.implementation.Implementation; | ||
import net.bytebuddy.implementation.bytecode.ByteCodeAppender; | ||
import net.bytebuddy.jar.asm.Label; | ||
import net.bytebuddy.jar.asm.MethodVisitor; | ||
import net.bytebuddy.jar.asm.Opcodes; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public final class FibClassGenerator { | ||
|
||
private static final String FIB_CLASS_NAME = "Fibonacci"; | ||
private static final String FUNCTION_NAME = "fib"; | ||
private static final int FUNCTION_OPERANDS_STACK_SIZE = 5; | ||
private static final String FUNCTION_SIGNATURE = "(I)J"; | ||
|
||
private FibClassGenerator() { | ||
} | ||
|
||
public static Object generate() { | ||
try (var unloaded = new ByteBuddy() | ||
.subclass(Object.class) | ||
.name(FIB_CLASS_NAME) | ||
.defineMethod(FUNCTION_NAME, long.class, Ownership.MEMBER, Visibility.PUBLIC) | ||
.withParameter(int.class, "n") | ||
.intercept(createFibImplementation()) | ||
.make() | ||
) { | ||
return unloaded.load(FibClassGenerator.class.getClassLoader()).getLoaded().getConstructor().newInstance(); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private static Implementation createFibImplementation() { | ||
return new Implementation.Simple(new FibByteCodeAppender()); | ||
} | ||
|
||
private final static class FibByteCodeAppender implements ByteCodeAppender { | ||
|
||
@Override | ||
@NotNull | ||
public Size apply( | ||
MethodVisitor methodVisitor, | ||
@NotNull Implementation.Context context, | ||
@NotNull MethodDescription methodDescription | ||
) { | ||
Label moreTwoLabel = new Label(); | ||
|
||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); | ||
methodVisitor.visitInsn(Opcodes.ICONST_2); | ||
methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, moreTwoLabel); | ||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); | ||
methodVisitor.visitInsn(Opcodes.I2L); | ||
methodVisitor.visitInsn(Opcodes.LRETURN); | ||
|
||
// more than 2 | ||
methodVisitor.visitLabel(moreTwoLabel); | ||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); | ||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); | ||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); | ||
methodVisitor.visitInsn(Opcodes.ICONST_1); | ||
methodVisitor.visitInsn(Opcodes.ISUB); | ||
|
||
// fib(n - 1) | ||
methodVisitor.visitMethodInsn( | ||
Opcodes.INVOKEVIRTUAL, | ||
FIB_CLASS_NAME, | ||
FUNCTION_NAME, | ||
FUNCTION_SIGNATURE, | ||
false | ||
); | ||
|
||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); | ||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); | ||
methodVisitor.visitInsn(Opcodes.ICONST_2); | ||
methodVisitor.visitInsn(Opcodes.ISUB); | ||
|
||
// fib(n - 2) | ||
methodVisitor.visitMethodInsn( | ||
Opcodes.INVOKEVIRTUAL, | ||
FIB_CLASS_NAME, | ||
FUNCTION_NAME, | ||
FUNCTION_SIGNATURE, | ||
false | ||
); | ||
methodVisitor.visitInsn(Opcodes.LADD); | ||
methodVisitor.visitInsn(Opcodes.LRETURN); | ||
// localVariableSize = 0 because Implementation.Simple creates variables | ||
// for parameters and I don`t use anything else | ||
return new ByteCodeAppender.Size(FUNCTION_OPERANDS_STACK_SIZE, 0); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package edu.hw11.task1; | ||
|
||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class HelloWorldCreatorTest { | ||
|
||
@Test | ||
@DisplayName("Тестирование HelloWorldCreator#createHelloWorld") | ||
public void createHelloWorld_shouldReturnObjectReturnsHelloWorld() { | ||
var helloWorld = HelloWorldCreator.createHelloWorld(); | ||
Assertions.assertThat(helloWorld.toString()).isEqualTo("Hello, ByteBuddy!"); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/test/java/edu/hw11/task2/ClassBehaviourReloaderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package edu.hw11.task2; | ||
|
||
import net.bytebuddy.agent.ByteBuddyAgent; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class ClassBehaviourReloaderTest { | ||
|
||
@Test | ||
@DisplayName("Тестирование ClassBehaviourReloader#reload") | ||
public void reload() { | ||
ByteBuddyAgent.install(); | ||
ClassBehaviourReloader.reload(); | ||
Assertions.assertThat(ArithmeticUtils.sum(5, 5)).isEqualTo(25); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package edu.hw11.task3; | ||
|
||
import java.lang.reflect.Method; | ||
import lombok.SneakyThrows; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class FibClassGeneratorTest { | ||
|
||
@SneakyThrows @Test | ||
@DisplayName("Тестирование FibClassGenerator#generate") | ||
public void generate() { | ||
Object object = FibClassGenerator.generate(); | ||
Class<?> clazz = object.getClass(); | ||
Method method = clazz.getMethod("fib", int.class); | ||
Object result = method.invoke(object, 10); | ||
Assertions.assertThat(result).isEqualTo(55L); | ||
} | ||
} |