Spring的小坑

这几天被奇怪的bug搞的头大,技术宅一开始都不知道发生了啥,后来我们合力搞明白了root cause

先放上Exception:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[junit] Testcase:
testDependencyExceptionHandler(com.amazon.calypso.document.tools.webapp.controller.SignatureHelperControllerTest): Caused an ERROR
[junit] Could not initialize class com.amazon.calypso.document.tools.webapp.util.LdapGroupControl$$EnhancerByMockitoWithCGLIB$$2918b0e4
[junit] java.lang.NoClassDefFoundError: Could not initialize class com.amazon.calypso.document.tools.webapp.util.LdapGroupControl$$EnhancerByMockitoWithCGLIB$$2918b0e4
[junit] at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
[junit] at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
[junit] at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
[junit] at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
[junit] at org.powermock.api.mockito.repackaged.ClassImposterizer.createProxy(ClassImposterizer.java:143)
[junit] at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:58)
[junit] at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
[junit] at org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
[junit] at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:46)
[junit] at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
[junit] at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
[junit] at org.mockito.Mockito.mock(Mockito.java:1285)
[junit] at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:33)
[junit] at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16)
[junit] at org.mockito.internal.configuration.DefaultAnnotationEngine.createMockFor(DefaultAnnotationEngine.java:43)
[junit] at org.mockito.internal.configuration.DefaultAnnotationEngine.process(DefaultAnnotationEngine.java:66)
[junit] at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:71)
[junit] at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:55)
[junit] at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:108)
[junit] at com.amazon.calypso.document.tools.webapp.controller.SignatureHelperControllerTest.setup(SignatureHelperControllerTest.java:56)

看起来是Mockito的问题,由于我们package用到了PowerMock 1.6.3(技术宅说他也不知道为啥用这个,他说应该找时间refactor去掉这个),不兼容Mockito 2.x,所以我们现在还在用Mockito 1.x,我一直以为bug是因为我引入的新package用到了Mockito 2.0的新特性,所以不兼容,于是我陷入了两难的境地。

不过!!在我看了个sage还是StackOverflow说他的controller和service不能一起跑unit test之后,我仿佛有了点思路,仔细研究了一下LdapGroupControl的class,突然发现有可能是我在其中用到了

1
2
final private String s1 = AppConfig.findString("aa.bb.cc");
final private String s2 = AppConfig.findString("aa.bb.dd");

然而这些个controller的unit test并没有initialize AppConfig,所以找不到这些String来初始化,给技术宅一说,技术宅觉得有可能,于是我就改成了@Value形式:

1
2
3
4
5
@Value("${aa.bb.cc}")
private String s1;
@Value("${aa.bb.dd}")
private String s2;

恩成功了!!!不报那个错误了!!!!

对的 报了另外一个错误 :)

还原一下当时的大概代码:

1
2
3
4
5
6
7
@Value("${aa.bb.cc}")
private String s1;
@Value("${aa.bb.dd}")
private String s2;
final private Map<EnumA, String> map = ImmutableMap.of(A.X, s1, A.Y, s2);

这个map疯狂报错,说映射结果是A.X = null。于是又一顿找原因为什么。我一度怀疑是我的@Value没有配置好。

疯狂操作疯狂试验…

疯狂操作疯狂试验…

疯狂操作疯狂试验…

疯狂操作疯狂试验…

结果最后还是在StackOverflow搜到了原因…有人把@Value标记的值加在了Constructor里,导致变量值为null,回答是Constructor的加载发生在Spring inject之前,所以会为null。恍然大悟,但是@PostConstruct annotation只适用于method level,对于attribute不适用,于是我直接把这个map放到了我需要用的method里面。。

解决了,build成功了,真是一堆坑。