Code generation for
alternative languages
and Java runtimes
interface Framework {
<T> Class<? extends T> secure(Class<T> type);
}
class Service {
@Secured(user = "ADMIN")
void deleteEverything() {
// delete everything...
}
}
@interface Secured {
String user();
}
class UserHolder {
static String user = "ANONYMOUS";
}
does not know aboutdepends on
discoversatruntime
class Service {
@Secured(user = "ADMIN")
void deleteEverything() {
if(!"ADMIN".equals(UserHolder.user)) {
throw new IllegalStateException("Wrong user");
}
// delete everything...
}
}
redefine class
(build time, agent)
create subclass
(Liskov substitution)
class SecuredService extends Service {
@Override
void deleteEverything() {
if(!"ADMIN".equals(UserHolder.user)) {
throw new IllegalStateException("Wrong user");
}
super.deleteEverything();
}
}
class Service {
@Secured(user = "ADMIN")
void deleteEverything() {
// delete everything...
}
}
0xCAFEBABE
source code
byte code
JVM
javac scalac groovyc jrubyc
JIT compilerinterpreter
class loader
creates
reads
runs
class Sample$MockitoMock extends Sample {
@Override String getValue() {
return Mockito.mock(this,
new Object[0],
Sample.class.getMethod("getValue"));
}
String original$getValue() {
return super.getValue();
}
@Override void setValue(String x) {
Mockito.mock(this,
new Object[] { x },
Sample.class.getMethod("setValue",
String.class));
}
void original$setValue(String x) {
super.setValue(x);
}
}
class Sample {
String value;
String getValue() {
return value;
}
void setValue(String x) {
this.value = x;
}
}
class Sample {
var value: String? = null
fun getValue() = value
fun setValue(x: String?) {
this.value = x
}
}
final class Sample {
String value;
final String getValue() {
return value;
}
final void setValue(String x) {
this.value = x;
}
}
open class Sample {
var value: String? = null
open fun getValue() = value
open fun setValue(x: String?) {
this.value = x
}
}
class Sample {
String value;
String getValue() {
return value;
}
void setValue(String x) {
this.value = x;
}
}
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>all-open</plugin>
</compilerPlugins>
<pluginOptions>
<option>all-open:annotation=pkg.MyOpen</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
annotation class MyOpen
final class Sample {
String value;
final String getValue() {
if (MockitoInfra.isMockMode(this)) {
return Mockito.mock( this,
new Object[0],
Sample.class.getMethod("getValue"));
} else {
return value;
}
}
final void setValue(String x) {
if (MockitoInfra.isMockMode(this)) {
Mockito.mock( this,
new Object[] { x },
Sample.class.getMethod("setValue",
String.class));
} else {
this.value = x;
}
}
}
final class Sample {
String value;
final String getValue() {
return value;
}
final void setValue(String x) {
this.value = x;
}
}
class MockitoInfra {
static final WeakConcurrentMap<Object, MockitoHandler> mocks;
static final ThreadLocal<Boolean> selfCall;
static boolean isMock(Object instance) {
return mocks.containsKey(instance);
}
static void registerMock(Object instance, MockHandler handler) {
mocks.put(instance, handler);
}
static boolean isMockMode(Object instance) {
return isMock(instance) && selfCall.get();
}
static void setMockMode(boolean mode) {
selfCall.set(mode);
}
}
https://github.com/raphw/weak-lock-free
package java.lang.instrumentation;
interface Instrumentation {
void addTransformer(ClassFileTransformer transformer, boolean retransform);
void retransformClasses(Class<?>... types);
void appendToBootstrapSearch(File file);
// ...
}
interface ClassFileTransformer {
byte[] transform(ClassLoader loader,
String name,
Class<?> type,
ProtectionDomain pd,
byte[] buffer);
}
NOPE!
Java virtual
machine
[stack, JIT]
Dalvik virtual
machine
[register, JIT]
Android
runtime
[register, AOT]
public class SimplePlugin implements Plugin {
@Override
public boolean matches(TypeDescription target) {
return target.getName().equals("Foo");
}
@Override
public DynamicType.Builder<?> apply(
DynamicType.Builder<?> builder,
TypeDescription typeDescription) {
return builder.method(named("bar"))
.intercept(value("Hello World!"));
}
}
https://github.com/raphw/byte-buddy
Build-time instrumentation with Maven.
<plugin>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>transform</goal>
</goals>
</execution>
</executions>
<configuration>
<transformations>
<transformation>
<plugin>pkg.SimplePlugin</plugin>
</transformation>
</transformations>
</configuration>
</plugin>
http://rafael.codes
@rafaelcodes
http://documents4j.com
https://github.com/documents4j/documents4j
http://bytebuddy.net
https://github.com/raphw/byte-buddy

Code generation for alternative languages