mirror of
https://github.com/google/guice.git
synced 2024-04-21 12:32:36 +00:00
By setting guice_include_stack_traces flag OFF, Guice does not collect stack traces for identifying the declaring source of a binding. Instead it uses the first non-skipped module class name from the modules stack. As a result, in some cases, error messages can be slightly different with this flag. For example, the file name and line number are not always available. A sample error message with this flag : Guice creation errors: 1) Received null converting foo (bound at com.google.inject.TypeConversionTest.configure(Unknown Source) (via modules: com.google.inject.TypeConversionTest -> com.google.inject.TypeConversionTest)) to java.util.Date using CustomConverter which matches only(java.util.Date) (bound at com.google.inject.TypeConversionTest.configure(Unknown Source) (via modules: com.google.inject.TypeConversionTest -> com.google.inject.TypeConversionTest -> com.google.inject.TypeConversionTest)). while locating java.util.Date annotated with @com.google.inject.TypeConversionTest() for field at com.google.inject.TypeConversionTest.date(TypeConversionTest.java:478) at com.google.inject.TypeConversionTest.configure(Unknown Source) (via modules: com.google.inject.TypeConversionTest -> com.google.inject.TypeConversionTest) This also changes the DEFAULT flag name to ONLY_FOR_DECLARTION_SOURCE. Adds InternalFlags.getIncludeStackTraceOption() to wrap system property access. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=53610378
350 lines
12 KiB
Java
350 lines
12 KiB
Java
/**
|
|
* Copyright (C) 2007 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.google.inject;
|
|
|
|
import static com.google.inject.Asserts.assertContains;
|
|
import static com.google.inject.Asserts.getDeclaringSourcePart;
|
|
import static com.google.inject.Asserts.reserialize;
|
|
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
|
import static java.lang.annotation.ElementType.FIELD;
|
|
import static java.lang.annotation.ElementType.METHOD;
|
|
import static java.lang.annotation.ElementType.PARAMETER;
|
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
|
|
import junit.framework.TestCase;
|
|
|
|
import java.io.IOException;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.Target;
|
|
|
|
/**
|
|
* @author jessewilson@google.com (Jesse Wilson)
|
|
*/
|
|
@SuppressWarnings("UnusedDeclaration")
|
|
public class ProvisionExceptionTest extends TestCase {
|
|
|
|
public void testExceptionsCollapsed() {
|
|
try {
|
|
Guice.createInjector().getInstance(A.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertTrue(e.getCause() instanceof UnsupportedOperationException);
|
|
assertContains(e.getMessage(), "Error injecting constructor",
|
|
"for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
|
|
"for field at com.google.inject.ProvisionExceptionTest$B.c",
|
|
"for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* There's a pass-through of user code in the scope. We want exceptions thrown by Guice to be
|
|
* limited to a single exception, even if it passes through user code.
|
|
*/
|
|
public void testExceptionsCollapsedWithScopes() {
|
|
try {
|
|
Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(B.class).in(Scopes.SINGLETON);
|
|
}
|
|
}).getInstance(A.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertTrue(e.getCause() instanceof UnsupportedOperationException);
|
|
assertFalse(e.getMessage().contains("custom provider"));
|
|
assertContains(e.getMessage(), "Error injecting constructor",
|
|
"for parameter 0 at com.google.inject.ProvisionExceptionTest$C.setD",
|
|
"for field at com.google.inject.ProvisionExceptionTest$B.c",
|
|
"for parameter 0 at com.google.inject.ProvisionExceptionTest$A");
|
|
}
|
|
}
|
|
|
|
public void testMethodInjectionExceptions() {
|
|
try {
|
|
Guice.createInjector().getInstance(E.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertTrue(e.getCause() instanceof UnsupportedOperationException);
|
|
assertContains(e.getMessage(), "Error injecting method",
|
|
"at " + E.class.getName() + ".setObject(ProvisionExceptionTest.java:");
|
|
}
|
|
}
|
|
|
|
public void testBindToProviderInstanceExceptions() {
|
|
try {
|
|
Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(D.class).toProvider(new DProvider());
|
|
}
|
|
}).getInstance(D.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertTrue(e.getCause() instanceof UnsupportedOperationException);
|
|
assertContains(e.getMessage(),
|
|
"1) Error in custom provider, java.lang.UnsupportedOperationException",
|
|
"at " + ProvisionExceptionTest.class.getName(),
|
|
getDeclaringSourcePart(getClass()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This test demonstrates that if the user throws a ProvisionException, we wrap it to add context.
|
|
*/
|
|
public void testProvisionExceptionsAreWrappedForBindToType() {
|
|
try {
|
|
Guice.createInjector().getInstance(F.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertContains(e.getMessage(), "1) User Exception",
|
|
"at " + F.class.getName() + ".<init>(ProvisionExceptionTest.java:");
|
|
}
|
|
}
|
|
|
|
public void testProvisionExceptionsAreWrappedForBindToProviderType() {
|
|
try {
|
|
Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(F.class).toProvider(FProvider.class);
|
|
}
|
|
}).getInstance(F.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertContains(e.getMessage(), "1) User Exception",
|
|
"while locating ", FProvider.class.getName(),
|
|
"while locating ", F.class.getName());
|
|
}
|
|
}
|
|
|
|
public void testProvisionExceptionsAreWrappedForBindToProviderInstance() {
|
|
try {
|
|
Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(F.class).toProvider(new FProvider());
|
|
}
|
|
}).getInstance(F.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertContains(e.getMessage(), "1) User Exception",
|
|
"at " + ProvisionExceptionTest.class.getName(),
|
|
getDeclaringSourcePart(getClass()));
|
|
}
|
|
}
|
|
|
|
public void testProvisionExceptionIsSerializable() throws IOException {
|
|
try {
|
|
Guice.createInjector().getInstance(A.class);
|
|
fail();
|
|
} catch (ProvisionException expected) {
|
|
ProvisionException reserialized = reserialize(expected);
|
|
assertContains(reserialized.getMessage(),
|
|
"1) Error injecting constructor, java.lang.UnsupportedOperationException",
|
|
"at com.google.inject.ProvisionExceptionTest$RealD.<init>()",
|
|
"at Key[type=com.google.inject.ProvisionExceptionTest$RealD, annotation=[none]]",
|
|
"@com.google.inject.ProvisionExceptionTest$C.setD()[0]",
|
|
"at Key[type=com.google.inject.ProvisionExceptionTest$C, annotation=[none]]",
|
|
"@com.google.inject.ProvisionExceptionTest$B.c",
|
|
"at Key[type=com.google.inject.ProvisionExceptionTest$B, annotation=[none]]",
|
|
"@com.google.inject.ProvisionExceptionTest$A.<init>()[0]",
|
|
"at Key[type=com.google.inject.ProvisionExceptionTest$A, annotation=[none]]");
|
|
}
|
|
}
|
|
|
|
public void testMultipleCauses() {
|
|
try {
|
|
Guice.createInjector().getInstance(G.class);
|
|
fail();
|
|
} catch (ProvisionException e) {
|
|
assertContains(e.getMessage(),
|
|
"1) Error injecting method, java.lang.IllegalArgumentException",
|
|
"Caused by: java.lang.IllegalArgumentException: java.lang.UnsupportedOperationException",
|
|
"Caused by: java.lang.UnsupportedOperationException: Unsupported",
|
|
"2) Error injecting method, java.lang.NullPointerException: can't inject second either",
|
|
"Caused by: java.lang.NullPointerException: can't inject second either",
|
|
"2 errors");
|
|
}
|
|
}
|
|
|
|
public void testInjectInnerClass() throws Exception {
|
|
Injector injector = Guice.createInjector();
|
|
try {
|
|
injector.getInstance(InnerClass.class);
|
|
fail();
|
|
} catch (Exception expected) {
|
|
assertContains(expected.getMessage(),
|
|
"Injecting into inner classes is not supported.",
|
|
"while locating " + InnerClass.class.getName());
|
|
}
|
|
}
|
|
|
|
public void testInjectLocalClass() throws Exception {
|
|
class LocalClass {}
|
|
|
|
Injector injector = Guice.createInjector();
|
|
try {
|
|
injector.getInstance(LocalClass.class);
|
|
fail();
|
|
} catch (Exception expected) {
|
|
assertContains(expected.getMessage(),
|
|
"Injecting into inner classes is not supported.",
|
|
"while locating " + LocalClass.class.getName());
|
|
}
|
|
}
|
|
|
|
public void testBindingAnnotationsOnMethodsAndConstructors() {
|
|
try {
|
|
Injector injector = Guice.createInjector();
|
|
injector.getInstance(MethodWithBindingAnnotation.class);
|
|
fail();
|
|
} catch (ConfigurationException expected) {
|
|
assertContains(expected.getMessage(), MethodWithBindingAnnotation.class.getName()
|
|
+ ".injectMe() is annotated with @", Green.class.getName() + "(), ",
|
|
"but binding annotations should be applied to its parameters instead.",
|
|
"while locating " + MethodWithBindingAnnotation.class.getName());
|
|
}
|
|
|
|
try {
|
|
Guice.createInjector().getInstance(ConstructorWithBindingAnnotation.class);
|
|
fail();
|
|
} catch (ConfigurationException expected) {
|
|
assertContains(expected.getMessage(), ConstructorWithBindingAnnotation.class.getName()
|
|
+ ".<init>() is annotated with @", Green.class.getName() + "(), ",
|
|
"but binding annotations should be applied to its parameters instead.",
|
|
"at " + ConstructorWithBindingAnnotation.class.getName() + ".class",
|
|
"while locating " + ConstructorWithBindingAnnotation.class.getName());
|
|
}
|
|
}
|
|
|
|
public void testBindingAnnotationWarningForScala() {
|
|
Injector injector = Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(String.class).annotatedWith(Green.class).toInstance("lime!");
|
|
}
|
|
});
|
|
injector.getInstance(LikeScala.class);
|
|
}
|
|
|
|
public void testLinkedBindings() {
|
|
Injector injector = Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(D.class).to(RealD.class);
|
|
}
|
|
});
|
|
|
|
try {
|
|
injector.getInstance(D.class);
|
|
fail();
|
|
} catch (ProvisionException expected) {
|
|
assertContains(expected.getMessage(),
|
|
"at " + RealD.class.getName() + ".<init>(ProvisionExceptionTest.java:",
|
|
"while locating " + RealD.class.getName(),
|
|
"while locating " + D.class.getName());
|
|
}
|
|
}
|
|
|
|
public void testProviderKeyBindings() {
|
|
Injector injector = Guice.createInjector(new AbstractModule() {
|
|
protected void configure() {
|
|
bind(D.class).toProvider(DProvider.class);
|
|
}
|
|
});
|
|
|
|
try {
|
|
injector.getInstance(D.class);
|
|
fail();
|
|
} catch (ProvisionException expected) {
|
|
assertContains(expected.getMessage(),
|
|
"while locating " + DProvider.class.getName(),
|
|
"while locating " + D.class.getName());
|
|
}
|
|
}
|
|
|
|
private class InnerClass {}
|
|
|
|
static class A {
|
|
@Inject
|
|
A(B b) { }
|
|
}
|
|
static class B {
|
|
@Inject C c;
|
|
}
|
|
static class C {
|
|
@Inject
|
|
void setD(RealD d) { }
|
|
}
|
|
static class E {
|
|
@Inject void setObject(Object o) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
static class MethodWithBindingAnnotation {
|
|
@Inject @Green void injectMe(String greenString) {}
|
|
}
|
|
|
|
static class ConstructorWithBindingAnnotation {
|
|
@Inject @Green ConstructorWithBindingAnnotation(String greenString) {}
|
|
}
|
|
|
|
/**
|
|
* In Scala, fields automatically get accessor methods with the same name. So we don't do
|
|
* misplaced-binding annotation detection if the offending method has a matching field.
|
|
*/
|
|
static class LikeScala {
|
|
@Inject @Green String green;
|
|
@Inject @Green String green() { return green; }
|
|
}
|
|
|
|
@Retention(RUNTIME)
|
|
@Target({ FIELD, PARAMETER, CONSTRUCTOR, METHOD })
|
|
@BindingAnnotation
|
|
@interface Green {}
|
|
|
|
interface D {}
|
|
|
|
static class RealD implements D {
|
|
@Inject RealD() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
static class DProvider implements Provider<D> {
|
|
public D get() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
static class F {
|
|
@Inject public F() {
|
|
throw new ProvisionException("User Exception", new RuntimeException());
|
|
}
|
|
}
|
|
|
|
static class FProvider implements Provider<F> {
|
|
public F get() {
|
|
return new F();
|
|
}
|
|
}
|
|
|
|
static class G {
|
|
@Inject void injectFirst() {
|
|
throw new IllegalArgumentException(new UnsupportedOperationException("Unsupported"));
|
|
}
|
|
@Inject void injectSecond() {
|
|
throw new NullPointerException("can't inject second either");
|
|
}
|
|
}
|
|
}
|