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