issue 574 - don't freak out on generated classes when trying to get line numbers.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@1492 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/core/src/com/google/inject/internal/util/LineNumbers.java b/core/src/com/google/inject/internal/util/LineNumbers.java
index ad5dbad..91bf389 100644
--- a/core/src/com/google/inject/internal/util/LineNumbers.java
+++ b/core/src/com/google/inject/internal/util/LineNumbers.java
@@ -58,8 +58,9 @@
if (!type.isArray()) {
InputStream in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
- Preconditions.checkArgument(in != null, "Cannot find bytecode for %s", type);
- new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
+ if (in != null) {
+ new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
+ }
}
}
diff --git a/core/test/com/google/inject/internal/util/LineNumbersTest.java b/core/test/com/google/inject/internal/util/LineNumbersTest.java
index 8566978..9ca5c38 100644
--- a/core/test/com/google/inject/internal/util/LineNumbersTest.java
+++ b/core/test/com/google/inject/internal/util/LineNumbersTest.java
@@ -21,8 +21,14 @@
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Inject;
+import com.google.inject.Injector;
import com.google.inject.matcher.Matchers;
+import java.lang.reflect.Modifier;
import junit.framework.TestCase;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
/**
* @author jessewilson@google.com (Jesse Wilson)
@@ -73,6 +79,63 @@
static class A {
@Inject A(B b) {}
}
- interface B {}
+ public interface B {}
+ static class GeneratingClassLoader extends ClassLoader {
+ static String name = "__generated";
+
+ GeneratingClassLoader() {
+ super(B.class.getClassLoader());
+ }
+
+ Class<?> generate() {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ cw.visit(Opcodes.V1_5, Modifier.PUBLIC, name, null, Type.getInternalName(Object.class), null);
+
+ String sig = "("+Type.getDescriptor(B.class)+")V";
+
+ MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "<init>", sig, null, null);
+
+ mv.visitAnnotation(Type.getDescriptor(Inject.class), true);
+ mv.visitCode();
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn( Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V" );
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ cw.visitEnd();
+
+ byte[] buf = cw.toByteArray();
+
+ return defineClass(name.replace('/', '.'), buf, 0, buf.length);
+ }
+ }
+
+ public void testUnavailableByteCodeShowsUnknownSource() {
+ try {
+ Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(new GeneratingClassLoader().generate());
+ }
+ });
+ fail();
+ } catch (CreationException expected) {
+ assertContains(expected.getMessage(),
+ "1) No implementation for " + B.class.getName() + " was bound.",
+ "for parameter 0 at " + GeneratingClassLoader.name + ".<init>(Unknown Source)",
+ "at " + LineNumbersTest.class.getName(), ".configure(LineNumbersTest.java:");
+ }
+ }
+
+ public void testGeneratedClassesCanSucceed() {
+ final Class<?> generated = new GeneratingClassLoader().generate();
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ bind(generated);
+ bind(B.class).toInstance(new B() {});
+ }
+ });
+ Object instance = injector.getInstance(generated);
+ assertEquals(instance.getClass(), generated);
+ }
}