1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dex.reader.util; 18 19 import java.io.IOException; 20 import java.util.Arrays; 21 import java.util.Collections; 22 import java.util.HashSet; 23 import java.util.Set; 24 25 import javax.tools.Diagnostic; 26 import javax.tools.DiagnosticCollector; 27 import javax.tools.JavaCompiler; 28 import javax.tools.JavaFileObject; 29 import javax.tools.StandardJavaFileManager; 30 import javax.tools.ToolProvider; 31 import javax.tools.JavaCompiler.CompilationTask; 32 33 import com.android.dx.dex.cf.CfOptions; 34 import com.android.dx.dex.cf.CfTranslator; 35 import com.android.dx.dex.file.ClassDefItem; 36 import com.android.dx.dex.file.DexFile; 37 38 import dex.reader.DexBuffer; 39 import dex.reader.DexFileReader; 40 41 public class JavaSourceToDexUtil { 42 getFrom(JavaSource source)43 public dex.structure.DexFile getFrom(JavaSource source) throws IOException{ 44 return getAllFrom(Collections.singleton(source)); 45 } 46 getFrom(JavaSource... source)47 public dex.structure.DexFile getFrom(JavaSource... source) throws IOException{ 48 return getAllFrom(new HashSet<JavaSource>(Arrays.asList(source))); 49 } 50 getAllFrom(Set<JavaSource> sources)51 public dex.structure.DexFile getAllFrom(Set<JavaSource> sources) throws IOException{ 52 return getFrom(sources, null); 53 } 54 55 /** 56 * Converts java source code to a {@link dex.structure.DexFile} loaded by 57 * {@link DexFileReader}. Converts only classes with the specified name in 58 * classesToDex or all classes if classesToDex is null. 59 * 60 * @throws IOException 61 */ getFrom(Set<JavaSource> sources, Set<String> classesToDex)62 public dex.structure.DexFile getFrom(Set<JavaSource> sources, 63 Set<String> classesToDex) throws IOException { 64 Set<MemoryByteCode> byteCodeInMemory = compileToByteCode(sources); 65 66 byte[] dexCode = convertToDexCode(byteCodeInMemory, classesToDex); 67 DexBuffer dexBuffer = new DexBuffer(dexCode); 68 DexFileReader reader = new DexFileReader(); 69 return reader.read(dexBuffer); 70 } 71 72 convertToDexCode(Set<MemoryByteCode> byteCodeInMemory, Set<String> classNamesToDex)73 private byte[] convertToDexCode(Set<MemoryByteCode> byteCodeInMemory, Set<String> classNamesToDex) throws IOException { 74 CfOptions cfOptions = new CfOptions(); 75 DexFile dexFile = new DexFile(); 76 for (MemoryByteCode memoryByteCode : byteCodeInMemory) { 77 if(classNamesToDex == null || classNamesToDex.contains(memoryByteCode.getName())) { 78 ClassDefItem classDefItem = CfTranslator.translate(memoryByteCode.getName().replace('.', '/') +".class", memoryByteCode.getBytes(), cfOptions); 79 dexFile.add(classDefItem); 80 } 81 } 82 return dexFile.toDex(null, false); 83 } 84 85 compileToByteCode(Set<JavaSource> source)86 public Set<MemoryByteCode> compileToByteCode(Set<JavaSource> source) { 87 JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 88 DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>(); 89 StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, 90 null, null); 91 SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm); 92 93 CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays 94 .asList(new String[] {"-classpath", "."}), null, source); 95 boolean success = compile.call(); 96 if(!success) { 97 StringBuilder errorMessage = new StringBuilder(); 98 for (Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) { 99 errorMessage.append(dia); 100 } 101 throw new IllegalStateException(errorMessage.toString()); 102 } 103 return xfm.getAllMemoryByteCodes(); 104 } 105 } 106 107 108 109 110 111 112