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