1/* 2 * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package separate; 25 26import java.io.*; 27import java.util.*; 28 29public class ClassToInterfaceConverter implements ClassFilePreprocessor { 30 31 private String whichClass; 32 33 public ClassToInterfaceConverter(String className) { 34 this.whichClass = className; 35 } 36 37 private boolean utf8Matches(ClassFile.CpEntry entry, String v) { 38 if (!(entry instanceof ClassFile.CpUtf8)) { 39 return false; 40 } 41 ClassFile.CpUtf8 utf8 = (ClassFile.CpUtf8)entry; 42 if (v.length() != utf8.bytes.length) { 43 return false; 44 } 45 for (int i = 0; i < v.length(); ++i) { 46 if (v.charAt(i) != utf8.bytes[i]) { 47 return false; 48 } 49 } 50 return true; 51 } 52 53 private void convertToInterface(ClassFile cf) { 54 cf.access_flags = 0x0601; // ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC 55 ArrayList<ClassFile.Method> new_methods = new ArrayList<>(); 56 // Find <init> method and delete it 57 for (int i = 0; i < cf.methods.size(); ++i) { 58 ClassFile.Method method = cf.methods.get(i); 59 ClassFile.CpEntry name = cf.constant_pool.get(method.name_index); 60 if (!utf8Matches(name, "<init>")) { 61 new_methods.add(method); 62 } 63 } 64 cf.methods = new_methods; 65 // Convert method tag. Find Methodref, which is not "<init>" and only invoked by other methods 66 // in the interface, convert it to InterfaceMethodref 67 ArrayList<ClassFile.CpEntry> cpool = new ArrayList<>(); 68 for (int i = 0; i < cf.constant_pool.size(); i++) { 69 ClassFile.CpEntry ce = cf.constant_pool.get(i); 70 if (ce instanceof ClassFile.CpMethodRef) { 71 ClassFile.CpMethodRef me = (ClassFile.CpMethodRef)ce; 72 ClassFile.CpNameAndType nameType = (ClassFile.CpNameAndType)cf.constant_pool.get(me.name_and_type_index); 73 ClassFile.CpEntry name = cf.constant_pool.get(nameType.name_index); 74 if (!utf8Matches(name, "<init>") && cf.this_class == me.class_index) { 75 ClassFile.CpInterfaceMethodRef newEntry = new ClassFile.CpInterfaceMethodRef(); 76 newEntry.class_index = me.class_index; 77 newEntry.name_and_type_index = me.name_and_type_index; 78 ce = newEntry; 79 } 80 } 81 cpool.add(ce); 82 } 83 cf.constant_pool = cpool; 84 } 85 86 public byte[] preprocess(String classname, byte[] bytes) { 87 ClassFile cf = new ClassFile(bytes); 88 89 ClassFile.CpEntry entry = cf.constant_pool.get(cf.this_class); 90 ClassFile.CpEntry name = cf.constant_pool.get( 91 ((ClassFile.CpClass)entry).name_index); 92 if (utf8Matches(name, whichClass)) { 93 convertToInterface(cf); 94 return cf.toByteArray(); 95 } else { 96 return bytes; // unmodified 97 } 98 } 99 100/* 101 public static void main(String argv[]) throws Exception { 102 File input = new File(argv[0]); 103 byte[] buffer = new byte[(int)input.length()]; 104 new FileInputStream(input).read(buffer); 105 106 ClassFilePreprocessor cfp = new ClassToInterfaceConverter("Hello"); 107 byte[] cf = cfp.preprocess(argv[0], buffer); 108 new FileOutputStream(argv[0] + ".mod").write(cf); 109 } 110*/ 111} 112