blob: 37cae97f32fdcb17bdae89637beac921f83c456a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * build @BUILD_TAG_PLACEHOLDER@
26 *
27 * @COPYRIGHT_MINI_LEGAL_NOTICE_PLACEHOLDER@
28 */
29
30import java.io.*;
31import java.lang.reflect.*;
32
33/*
34 ClassLoader that knows how to fabricate exactly one class. The name
35 of the class is defined by the parameter singleClassName. When
36 asked to load a class, this loader first delegates to its parent as
37 usual, then, if that doesn't find the class and if the name is the
38 same as singleClassName, the class is fabricated. It is a public
39 class with no fields or methods and a single public no-arg
40 constructor that simply calls its parent's no-arg constructor. This
41 means that the parent must have a public or protected no-arg
42 constructor.
43 */
44public class SingleClassLoader extends ClassLoader {
45 SingleClassLoader(String singleClassName, Class superclass,
46 ClassLoader parent) {
47 super(parent);
48
49 Constructor superConstr;
50 try {
51 superConstr = superclass.getDeclaredConstructor(new Class[0]);
52 } catch (NoSuchMethodException e) {
53 throw new IllegalArgumentException("Superclass must have no-arg " +
54 "constructor");
55 }
56 int superConstrMods = superConstr.getModifiers();
57 if ((superConstrMods & (Modifier.PUBLIC|Modifier.PROTECTED)) == 0) {
58 final String msg =
59 "Superclass no-arg constructor must be public or protected";
60 throw new IllegalArgumentException(msg);
61 }
62
63 this.singleClassName = singleClassName;
64 final Class c;
65 try {
66 c = makeClass(superclass);
67 } catch (IOException e) {
68 throw new RuntimeException(e.toString());
69 }
70 this.singleClass = c;
71 }
72
73 private Class makeClass(Class superclass) throws IOException {
74 final String superName = superclass.getName();
75
76 ByteArrayOutputStream bout = new ByteArrayOutputStream();
77 dout = new DataOutputStream(bout);
78
79 String thisNameInternal = singleClassName.replace('.', '/');
80 String superNameInternal = superName.replace('.', '/');
81
82 dout.writeInt(0xcafebabe); // magic
83 dout.writeInt(0x0003002d); // major 45 minor 3
84 dout.writeShort(10); // cpool count (incl virtual 0 element)
85
86 cpoolIndex = 1;
87
88 int thisNameConst = writeUTFConst(thisNameInternal);
89 int thisClassConst = writeClassConst(thisNameConst);
90 int superNameConst = writeUTFConst(superNameInternal);
91 int superClassConst = writeClassConst(superNameConst);
92 int initNameConst = writeUTFConst("<init>");
93 int voidNoArgSigConst = writeUTFConst("()V");
94 int codeNameConst = writeUTFConst("Code");
95 int superConstructorNameAndTypeConst =
96 writeNameAndTypeConst(initNameConst, voidNoArgSigConst);
97 int superConstructorMethodRefConst =
98 writeMethodRefConst(superClassConst,
99 superConstructorNameAndTypeConst);
100
101 dout.writeShort(Modifier.PUBLIC | 0x20 /*SUPER*/);
102 dout.writeShort(thisClassConst);
103 dout.writeShort(superClassConst);
104 dout.writeInt(0); // n interfaces, n fields
105 dout.writeShort(1); // n methods
106
107 // <init> method
108 dout.writeShort(Modifier.PUBLIC);
109 dout.writeShort(initNameConst);
110 dout.writeShort(voidNoArgSigConst);
111 dout.writeShort(1); // attr count
112
113 // Code attribute
114 dout.writeShort(codeNameConst);
115 dout.writeInt(17); // len
116 dout.writeShort(1); // max stack
117 dout.writeShort(1); // max locals
118 dout.writeInt(5); // code len
119 dout.writeByte(42); // aload_0
120 dout.writeByte(183); // invokespecial
121 dout.writeShort(superConstructorMethodRefConst);
122 dout.writeByte(177); // return
123
124 dout.writeShort(0); // 0 catches
125
126 dout.writeShort(0); // 0 method attrs
127
128 dout.writeShort(0); // 0 class attrs
129
130 dout.close();
131 byte[] classBytes = bout.toByteArray();
132
133 dout = null;
134
135 return
136 defineClass(singleClassName, classBytes, 0, classBytes.length);
137 }
138
139 protected Class findClass(String name) throws ClassNotFoundException {
140 if (name.equals(singleClassName))
141 return singleClass;
142 else
143 throw new ClassNotFoundException(name);
144 }
145
146 private int writeUTFConst(String s) throws IOException {
147 dout.writeByte(1);
148 dout.writeUTF(s);
149 return cpoolIndex++;
150 }
151
152 private int writeClassConst(int nameIndex) throws IOException {
153 dout.writeByte(7);
154 dout.writeShort((short) nameIndex);
155 return cpoolIndex++;
156 }
157
158 private int writeNameAndTypeConst(int nameIndex, int typeIndex)
159 throws IOException {
160 dout.writeByte(12);
161 dout.writeShort((short) nameIndex);
162 dout.writeShort((short) typeIndex);
163 return cpoolIndex++;
164 }
165
166 private int writeMethodRefConst(int classIndex, int nameAndTypeIndex)
167 throws IOException {
168 dout.writeByte(10);
169 dout.writeShort((short) classIndex);
170 dout.writeShort((short) nameAndTypeIndex);
171 return cpoolIndex++;
172 }
173
174 private final String singleClassName;
175 private final Class singleClass;
176
177 private DataOutputStream dout;
178 private int cpoolIndex;
179}