Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion libraries/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</plugins>
</build>

<dependencies>
<dependencies>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
Expand Down Expand Up @@ -51,6 +51,11 @@
<artifactId>javatuples</artifactId>
<version>${javatuples.version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javaassist.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
<dependency>
<groupId>org.assertj</groupId>
Expand All @@ -65,6 +70,7 @@
<junit.version>4.12</junit.version>
<jasypt.version>1.9.2</jasypt.version>
<javatuples.version>1.2</javatuples.version>
<javaassist.version>3.21.0-GA</javaassist.version>
<assertj.version>3.6.2</assertj.version>
</properties>

Expand Down
17 changes: 17 additions & 0 deletions libraries/src/main/java/com/baeldung/javasisst/Point.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.baeldung.javasisst;


public class Point {
public int x = 0;
public int y = 0;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public void move(int x, int y) {
this.x = x;
this.y = y;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.baeldung.javasisst;


public class ThreeDimensionalPoint {
public int x = 0;
public int y = 0;
public int z = 0;

public ThreeDimensionalPoint(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}

public void move(int x, int y) {
this.x = x;
this.y = y;
}
}
119 changes: 119 additions & 0 deletions libraries/src/test/java/com/baeldung/javassist/JavasisstTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.baeldung.javassist;


import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.NotFoundException;
import javassist.bytecode.*;
import org.junit.Test;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class JavasisstTest {
@Test
public void givenJavasisstAPI_whenConstructClass_thenGenerateAClassFile() throws CannotCompileException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
//given
String classNameWithPackage = "com.baeldung.JavassistGeneratedClass";
ClassFile cf = new ClassFile(false, classNameWithPackage, null);
cf.setInterfaces(new String[]{"java.lang.Cloneable"});

FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);

//when
String className = "JavassistGeneratedClass.class";
cf.write(new DataOutputStream(new FileOutputStream(className)));

//then
ClassPool classPool = ClassPool.getDefault();
Field[] fields = classPool.makeClass(cf).toClass().getFields();
assertEquals(fields[0].getName(), "id");

String classContent = new String(Files.readAllBytes(Paths.get(className)));
assertTrue(classContent.contains("java/lang/Cloneable"));
}

@Test
public void givenJavaClass_whenLoadAtByJavassist_thenTraversWholeClass() throws NotFoundException, CannotCompileException, BadBytecode {
//given
ClassPool cp = ClassPool.getDefault();
ClassFile cf = cp.get("com.baeldung.javasisst.Point").getClassFile();
MethodInfo minfo = cf.getMethod("move");
CodeAttribute ca = minfo.getCodeAttribute();
CodeIterator ci = ca.iterator();

//when
List<String> operations = new LinkedList<>();
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
operations.add(Mnemonic.OPCODE[op]);
}

//then
assertEquals(operations,
Arrays.asList("aload_0", "iload_1", "putfield", "aload_0", "iload_2", "putfield", "return"));

}

@Test
public void givenTableOfInstructions_whenAddNewInstruction_thenShouldConstructProperSequence() throws NotFoundException, BadBytecode, CannotCompileException, IllegalAccessException, InstantiationException {
//given
ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.ThreeDimensionalPoint").getClassFile();

//when
FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);


ClassPool classPool = ClassPool.getDefault();
Field[] fields = classPool.makeClass(cf).toClass().getFields();
List<String> fieldsList = Stream.of(fields).map(Field::getName).collect(Collectors.toList());
assertTrue(fieldsList.contains("id"));

}

@Test
public void givenLoadedClass_whenAddConstructorToClass_shouldCreateClassWithConstructor() throws NotFoundException, CannotCompileException, BadBytecode {
//given
ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.Point").getClassFile();
Bytecode code = new Bytecode(cf.getConstPool());
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);

//when
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);

//then
CodeIterator ci = code.toCodeAttribute().iterator();
List<String> operations = new LinkedList<>();
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
operations.add(Mnemonic.OPCODE[op]);
}

assertEquals(operations,
Arrays.asList("aload_0", "invokespecial", "return"));


}
}