1 /** 2 * Copyright (C) 2008 Google Inc. 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 com.google.inject.internal.util; 18 19 import static com.google.inject.Asserts.assertContains; 20 import static com.google.inject.Asserts.getDeclaringSourcePart; 21 22 import com.google.inject.AbstractModule; 23 import com.google.inject.CreationException; 24 import com.google.inject.Guice; 25 import com.google.inject.Injector; 26 import com.google.inject.matcher.Matchers; 27 28 import junit.framework.TestCase; 29 30 import java.lang.reflect.Modifier; 31 32 import javax.inject.Inject; 33 34 /** 35 * @author jessewilson@google.com (Jesse Wilson) 36 */ 37 public class LineNumbersTest extends TestCase { 38 testLineNumbers()39 public void testLineNumbers() { 40 try { 41 Guice.createInjector(new AbstractModule() { 42 protected void configure() { 43 bind(A.class); 44 } 45 }); 46 fail(); 47 } catch (CreationException expected) { 48 assertContains(expected.getMessage(), 49 "1) No implementation for " + B.class.getName() + " was bound.", 50 "for parameter 0 at " + A.class.getName() + ".<init>(LineNumbersTest.java:", 51 "at " + LineNumbersTest.class.getName(), getDeclaringSourcePart(getClass())); 52 } 53 } 54 55 static class A { A(B b)56 @Inject A(B b) {} 57 } 58 public interface B {} 59 60 /*if[AOP]*/ testCanHandleLineNumbersForGuiceGeneratedClasses()61 public void testCanHandleLineNumbersForGuiceGeneratedClasses() { 62 try { 63 Guice.createInjector(new AbstractModule() { 64 protected void configure() { 65 bindInterceptor(Matchers.only(A.class), Matchers.any(), 66 new org.aopalliance.intercept.MethodInterceptor() { 67 public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation) { 68 return null; 69 } 70 }); 71 72 bind(A.class); 73 } 74 }); 75 fail(); 76 } catch (CreationException expected) { 77 assertContains(expected.getMessage(), 78 "1) No implementation for " + B.class.getName() + " was bound.", 79 "for parameter 0 at " + A.class.getName() + ".<init>(LineNumbersTest.java:", 80 "at " + LineNumbersTest.class.getName(), getDeclaringSourcePart(getClass())); 81 } 82 } 83 84 static class GeneratingClassLoader extends ClassLoader { 85 static String name = "__generated"; 86 GeneratingClassLoader()87 GeneratingClassLoader() { 88 super(B.class.getClassLoader()); 89 } 90 generate()91 Class<?> generate() { 92 org.objectweb.asm.ClassWriter cw = 93 new org.objectweb.asm.ClassWriter(org.objectweb.asm.ClassWriter.COMPUTE_MAXS); 94 cw.visit(org.objectweb.asm.Opcodes.V1_5, 95 Modifier.PUBLIC, name, null, 96 org.objectweb.asm.Type.getInternalName(Object.class), null); 97 98 String sig = "("+org.objectweb.asm.Type.getDescriptor(B.class)+")V"; 99 100 org.objectweb.asm.MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "<init>", sig, null, null); 101 102 mv.visitAnnotation(org.objectweb.asm.Type.getDescriptor(Inject.class), true); 103 mv.visitCode(); 104 mv.visitVarInsn(org.objectweb.asm.Opcodes.ALOAD, 0); 105 mv.visitMethodInsn(org.objectweb.asm.Opcodes.INVOKESPECIAL, 106 org.objectweb.asm.Type.getInternalName(Object.class), "<init>", "()V" ); 107 mv.visitInsn(org.objectweb.asm.Opcodes.RETURN); 108 mv.visitMaxs(0, 0); 109 mv.visitEnd(); 110 cw.visitEnd(); 111 112 byte[] buf = cw.toByteArray(); 113 114 return defineClass(name.replace('/', '.'), buf, 0, buf.length); 115 } 116 } 117 testUnavailableByteCodeShowsUnknownSource()118 public void testUnavailableByteCodeShowsUnknownSource() { 119 try { 120 Guice.createInjector(new AbstractModule() { 121 protected void configure() { 122 bind(new GeneratingClassLoader().generate()); 123 } 124 }); 125 fail(); 126 } catch (CreationException expected) { 127 assertContains(expected.getMessage(), 128 "1) No implementation for " + B.class.getName() + " was bound.", 129 "for parameter 0 at " + GeneratingClassLoader.name + ".<init>(Unknown Source)", 130 "at " + LineNumbersTest.class.getName(), getDeclaringSourcePart(getClass())); 131 } 132 } 133 testGeneratedClassesCanSucceed()134 public void testGeneratedClassesCanSucceed() { 135 final Class<?> generated = new GeneratingClassLoader().generate(); 136 Injector injector = Guice.createInjector(new AbstractModule() { 137 protected void configure() { 138 bind(generated); 139 bind(B.class).toInstance(new B() {}); 140 } 141 }); 142 Object instance = injector.getInstance(generated); 143 assertEquals(instance.getClass(), generated); 144 } 145 /*end[AOP]*/ 146 } 147