xref: /aosp_15_r20/external/dexmaker/README.md (revision 2ffc472c461b441c3ddd38c52c72da5a6be8f680)
1*2ffc472cSXin LiA Java-language API for doing compile time or runtime code generation targeting the Dalvik VM. Unlike
2*2ffc472cSXin Li[cglib](http://cglib.sourceforge.net/) or [ASM](http://asm.ow2.org/), this library creates Dalvik `.dex`
3*2ffc472cSXin Lifiles instead of Java `.class` files.
4*2ffc472cSXin Li
5*2ffc472cSXin LiIt has a small, close-to-the-metal API. This API mirrors the
6*2ffc472cSXin Li[Dalvik bytecode specification](http://source.android.com/tech/dalvik/dalvik-bytecode.html) giving you tight
7*2ffc472cSXin Licontrol over the bytecode emitted. Code is generated instruction-by-instruction; you bring your own abstract
8*2ffc472cSXin Lisyntax tree if you need one. And since it uses Dalvik's `dx` tool as a backend, you get efficient register
9*2ffc472cSXin Liallocation and regular/wide instruction selection for free.
10*2ffc472cSXin Li
11*2ffc472cSXin LiClass Proxies
12*2ffc472cSXin Li-------------
13*2ffc472cSXin Li
14*2ffc472cSXin LiDexmaker includes a stock code generator for [class proxies](http://dexmaker.googlecode.com/git/javadoc/com/google/dexmaker/stock/ProxyBuilder.html).
15*2ffc472cSXin LiIf you just want to do AOP or class mocking, you don't need to mess around with bytecodes.
16*2ffc472cSXin Li
17*2ffc472cSXin LiMockito Mocks
18*2ffc472cSXin Li-------------
19*2ffc472cSXin Li
20*2ffc472cSXin LiDexmaker includes class proxy support for [Mockito](http://code.google.com/p/mockito/). Add the mockito
21*2ffc472cSXin Liand the dexmaker `.jar` files to your Android test project's `libs/` directory and you can use Mockito
22*2ffc472cSXin Liin your Android unit tests.
23*2ffc472cSXin Li
24*2ffc472cSXin LiThis requires Mockito 1.10.5 or newer.
25*2ffc472cSXin Li
26*2ffc472cSXin LiRuntime Code Generation
27*2ffc472cSXin Li-----------------------
28*2ffc472cSXin Li
29*2ffc472cSXin LiThis example generates a class and a method. It then loads that class into the current process and invokes its method.
30*2ffc472cSXin Li```
31*2ffc472cSXin Lipublic final class HelloWorldMaker {
32*2ffc472cSXin Li    public static void main(String[] args) throws Exception {
33*2ffc472cSXin Li        DexMaker dexMaker = new DexMaker();
34*2ffc472cSXin Li
35*2ffc472cSXin Li        // Generate a HelloWorld class.
36*2ffc472cSXin Li        TypeId<?> helloWorld = TypeId.get("LHelloWorld;");
37*2ffc472cSXin Li        dexMaker.declare(helloWorld, "HelloWorld.generated", Modifier.PUBLIC, TypeId.OBJECT);
38*2ffc472cSXin Li        generateHelloMethod(dexMaker, helloWorld);
39*2ffc472cSXin Li
40*2ffc472cSXin Li        // Create the dex file and load it.
41*2ffc472cSXin Li        File outputDir = new File(".");
42*2ffc472cSXin Li        ClassLoader loader = dexMaker.generateAndLoad(HelloWorldMaker.class.getClassLoader(),
43*2ffc472cSXin Li                outputDir, outputDir);
44*2ffc472cSXin Li        Class<?> helloWorldClass = loader.loadClass("HelloWorld");
45*2ffc472cSXin Li
46*2ffc472cSXin Li        // Execute our newly-generated code in-process.
47*2ffc472cSXin Li        helloWorldClass.getMethod("hello").invoke(null);
48*2ffc472cSXin Li    }
49*2ffc472cSXin Li
50*2ffc472cSXin Li    /**
51*2ffc472cSXin Li     * Generates Dalvik bytecode equivalent to the following method.
52*2ffc472cSXin Li     *    public static void hello() {
53*2ffc472cSXin Li     *        int a = 0xabcd;
54*2ffc472cSXin Li     *        int b = 0xaaaa;
55*2ffc472cSXin Li     *        int c = a - b;
56*2ffc472cSXin Li     *        String s = Integer.toHexString(c);
57*2ffc472cSXin Li     *        System.out.println(s);
58*2ffc472cSXin Li     *        return;
59*2ffc472cSXin Li     *    }
60*2ffc472cSXin Li     */
61*2ffc472cSXin Li    private static void generateHelloMethod(DexMaker dexMaker, TypeId<?> declaringType) {
62*2ffc472cSXin Li        // Lookup some types we'll need along the way.
63*2ffc472cSXin Li        TypeId<System> systemType = TypeId.get(System.class);
64*2ffc472cSXin Li        TypeId<PrintStream> printStreamType = TypeId.get(PrintStream.class);
65*2ffc472cSXin Li
66*2ffc472cSXin Li        // Identify the 'hello()' method on declaringType.
67*2ffc472cSXin Li        MethodId hello = declaringType.getMethod(TypeId.VOID, "hello");
68*2ffc472cSXin Li
69*2ffc472cSXin Li        // Declare that method on the dexMaker. Use the returned Code instance
70*2ffc472cSXin Li        // as a builder that we can append instructions to.
71*2ffc472cSXin Li        Code code = dexMaker.declare(hello, Modifier.STATIC | Modifier.PUBLIC);
72*2ffc472cSXin Li
73*2ffc472cSXin Li        // Declare all the locals we'll need up front. The API requires this.
74*2ffc472cSXin Li        Local<Integer> a = code.newLocal(TypeId.INT);
75*2ffc472cSXin Li        Local<Integer> b = code.newLocal(TypeId.INT);
76*2ffc472cSXin Li        Local<Integer> c = code.newLocal(TypeId.INT);
77*2ffc472cSXin Li        Local<String> s = code.newLocal(TypeId.STRING);
78*2ffc472cSXin Li        Local<PrintStream> localSystemOut = code.newLocal(printStreamType);
79*2ffc472cSXin Li
80*2ffc472cSXin Li        // int a = 0xabcd;
81*2ffc472cSXin Li        code.loadConstant(a, 0xabcd);
82*2ffc472cSXin Li
83*2ffc472cSXin Li        // int b = 0xaaaa;
84*2ffc472cSXin Li        code.loadConstant(b, 0xaaaa);
85*2ffc472cSXin Li
86*2ffc472cSXin Li        // int c = a - b;
87*2ffc472cSXin Li        code.op(BinaryOp.SUBTRACT, c, a, b);
88*2ffc472cSXin Li
89*2ffc472cSXin Li        // String s = Integer.toHexString(c);
90*2ffc472cSXin Li        MethodId<Integer, String> toHexString
91*2ffc472cSXin Li                = TypeId.get(Integer.class).getMethod(TypeId.STRING, "toHexString", TypeId.INT);
92*2ffc472cSXin Li        code.invokeStatic(toHexString, s, c);
93*2ffc472cSXin Li
94*2ffc472cSXin Li        // System.out.println(s);
95*2ffc472cSXin Li        FieldId<System, PrintStream> systemOutField = systemType.getField(printStreamType, "out");
96*2ffc472cSXin Li        code.sget(systemOutField, localSystemOut);
97*2ffc472cSXin Li        MethodId<PrintStream, Void> printlnMethod = printStreamType.getMethod(
98*2ffc472cSXin Li                TypeId.VOID, "println", TypeId.STRING);
99*2ffc472cSXin Li        code.invokeVirtual(printlnMethod, null, localSystemOut, s);
100*2ffc472cSXin Li
101*2ffc472cSXin Li        // return;
102*2ffc472cSXin Li        code.returnVoid();
103*2ffc472cSXin Li    }
104*2ffc472cSXin Li}
105*2ffc472cSXin Li```
106*2ffc472cSXin Li
107*2ffc472cSXin LiUse it in your app
108*2ffc472cSXin Li------------------
109*2ffc472cSXin Li
110*2ffc472cSXin LiFor Mockito support, download the latest .jar via Maven:
111*2ffc472cSXin Li```xml
112*2ffc472cSXin Li    <dependency>
113*2ffc472cSXin Li      <groupId>com.linkedin.dexmaker</groupId>
114*2ffc472cSXin Li      <artifactId>dexmaker-mockito</artifactId>
115*2ffc472cSXin Li      <version>2.25.0</version>
116*2ffc472cSXin Li      <type>pom</type>
117*2ffc472cSXin Li    </dependency>
118*2ffc472cSXin Li```
119*2ffc472cSXin Li
120*2ffc472cSXin Li```
121*2ffc472cSXin Li    androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.25.0'
122*2ffc472cSXin Li```
123*2ffc472cSXin Li
124*2ffc472cSXin LiDownload [dexmaker-1.2.jar](http://search.maven.org/remotecontent?filepath=com/google/dexmaker/dexmaker/1.2/dexmaker-1.2.jar)
125*2ffc472cSXin Liand [dexmaker-mockito-1.2.jar](http://search.maven.org/remotecontent?filepath=com/google/dexmaker/dexmaker-mockito/1.2/dexmaker-mockito-1.2.jar).
126*2ffc472cSXin Li
127*2ffc472cSXin LiRun the Unit Tests
128*2ffc472cSXin Li------------------
129*2ffc472cSXin Li
130*2ffc472cSXin LiThe unit tests for dexmaker must be run on a dalvikvm. In order to do this, you can use [Vogar](https://code.google.com/p/vogar/) in the following fashion:
131*2ffc472cSXin Li
132*2ffc472cSXin Li```
133*2ffc472cSXin Li$ java -jar vogar.jar --mode device --sourcepath /path/to/dexmaker/dexmaker/src/test/java --sourcepath /path/to/dexmaker/dexmaker/src/main/java --sourcepath /path/to/dexmaker/dx/src/main/java --device-dir /data/dexmaker /path/to/dexmaker/dexmaker/src/test/
134*2ffc472cSXin Li```
135*2ffc472cSXin Li
136*2ffc472cSXin LiDownload [vogar.jar](https://vogar.googlecode.com/files/vogar.jar).
137