java.lang.ExceptionInInitializerError when mocking static method using EasyMock+PowerMock - java

I am trying to mock static method using EasyMock+PowerMock. If I dont mock the static method, then I get the exception java.lang.ExceptionInInitializerError but with a different stack trace which is purely due to my code files and the error is obvious. However, if I mock the static method using EasyMock+PowerMock, the line PowerMock.mockStaticNice(Classname.class) throws the same exception but with a different stack trace. The stack trace is:
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:386)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:175)
at org.easymock.internal.MocksControl.createMock(MocksControl.java:114)
at org.easymock.internal.MocksControl.createMock(MocksControl.java:88)
at org.easymock.internal.MocksControl.createMock(MocksControl.java:79)
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2212)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
at org.powermock.api.easymock.PowerMock.mockStaticNice(PowerMock.java:331)
at PackageName(ClassName.java:125)
............................
The line 125 is PowerMock.mockStaticNice(Classname.class)
I have already tried this:
1) Mention class name containing static method in PrepareForTest({class1.class, class2.class, class3.class})
2) Mock static methods in #Before annotation.
I am stuck with this problem for the last 2 days. Kindly suggest solutions.

As I understood from your explanation the ExceptionInInitializerError is thrown during static initialisation of class? I've made such conclusion, because according to stacktrace the line PowerMock.mockStaticNice(Classname.class) is a first place where the class Classname is being loaded.
In this case you have to use #SuppressStaticInitializationFor(PackageName.ClassName`). More information you may find in PowerMock documentation: Suppress Unwanted Behavior

Related

Lambda - ClassNotFoundException

Here is what my code looks like, and it is unclear how/why executorService.submit(work::get) would throw a ClassNotFoundException on the anonymous class in question. It does not happen all the time, but once this exception is encountered, it does not seem to recover - subsequent requests are then met with the same exceptions. Anyone know what could be causing this to occur?
EDIT: I can confirm that either all calls to this method work, or none does, in a VM session - it is not like some succeed while others fail due to the said exception.
Further edit: https://bugs.openjdk.java.net/browse/JDK-8148560 is the exactly the bug I am experiencing, but that one was closed since it was not reproducible and/or the reporter did not respond. It somehow looks like the anonymous type resulting from the lambda expression is garbage collected before the executor gets to execute the expression, but obviously not always. The jdk in use is openjdk1.8.0_221.
package com.ab.cde.ct.service.impl;
#Service
public class IngestionService {
#Autowired private TransactionTemplate transactionTemplate;
#Autowired private AsyncTaskExecutor executorService;
#Transactional
public void ingest(Data data) {
Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
// actual work on the data object, enclosed in a try/catch/finally
});
executorService.submit(work::get); // this is where the exception gets thrown
}
}
Here is what the exception stacktrace looks like (line nos. won't correspond since the code above is only a prototype):
2019-10-23 19:11:35,267|[http-apr-26001-exec-10]|[B6AC864143092042BBB4A0876BB51EB6.1]|[]|[ERROR] web.error.ErrorServlet [line:142] org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
at org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1275)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:951)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:867)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:951)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:853)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
Caused by: java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
at com.ab.cde.ct.service.impl.IngestionService$$Lambda$53/812375226.get$Lambda(Unknown Source)
at com.ab.cde.ct.service.impl.IngestionService.ingest(IngestionService.java:264)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy252.ingest(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.ab.cde.ct.service.impl.IngestionService$$Lambda$53
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1364)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1185)
... 115 more
This is the case of synthetic method generated by lambda which is unable to find the required class (i.e. TransactionCallback) and thus the below error
Caused by: java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
at com.ab.cde.ct.service.impl.IngestionService$$Lambda$53/812375226.get$Lambda(Unknown Source)
The particular code which causes this issue is
Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
// actual work on the data object, enclosed in a try/catch/finally
});
To get past this modify the code as below
TransactionCallback<Optional<String>> callback = transactionStatus -> {
// your processing goes here
return Optional.of("some value");
};
Supplier<Optional<String>> work = () -> transactionTemplate.execute(callback);
If above still doesn't work use below workaround
Object callback = (TransactionCallback<Optional<String>>)transactionStatus -> {
// your processing goes here
return Optional.of("some value");
};
Supplier<Optional<String>> work = () -> transactionTemplate.execute((TransactionCallback<Optional<String>>)callback);
Do let know in comments if any more information is required.
P.S.: There is no need for #Transactional if transactionTemplate is being used as both essentially serves the same purpose.
References:
Lambda compilation here and here
Synthetic methods in java
I've had this before with both DI issues and with ambiguity bugs/config problems in package resolution. I'm assuming from your post that the error happens after successful startup, and exactly on invocation of that line in the method, and can be hit in the debugger.
First suggestion:
With Gradle/Maven, check dependent packages to make sure everything has the version it needs, and you aren't overriding a version globally that may affect a dependent package that requires a higher or lower version of that dependency.
Some low hanging fruit to try first (if it is easy enough to pick):
Update your JDK version or Java version (or see if another dev on your team has a different version and they can repro the issue)
Update your version of spring (even a minor version)
Update your IDE
Add logging and check if the issue can be reproduced in release environments.
Regarding dependency injection,
I would recommend trying something like the following.. and is also a good practice for dependency injection in spring, as it gives spring a more explicit dependency map, and increases your ability to debug the application dependencies.
#Service
public class IngestionService {
private TransactionTemplate transactionTemplate;
private AsyncTaskExecutor executorService;
public IngestionService(TransactionTemplate transactionTemplate, AsyncTaskExecutor executorService) {
this.transactionTemplate = transactionTemplate;
this.executorService = executorService;
}
#Transactional
public void ingest(Data data) {
Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
// actual work on the data object, enclosed in a try/catch/finally
});
executorService.submit(work::get); // this is where the exception gets thrown
}
}
There are a few reasons I recommend this:
In java, when no constructor is defined, it is implied that there is a default constructor, and the compiler will generate a constructor for you. To spring, this can be confusing and also decrease performance.
Defining this constructor explicitly tells Spring: I'm relying on these two dependencies which I also have setup as Beans that will be non-null and fully resolved on construction. You must initialize those dependencies first and pass them in before this can be a valid object.
This helps in debugging, you can set a breakpoint in the constructor and validate what is coming in.
If there is an issue with your bean setup for the dependencies, Spring will explode. The spring stack traces aren't always the most helpful, but it may help you debug any issue where you're not fully isolating and declaring beans you depend on in the correct way.
It allows you to eliminate the possibility of any issues with injection, both from the Spring Framework point of view (hard to tell what happens behind the scenes), and from your application/domain logic point of view. If it is still null later, you'd have been able to debug what was passed in the constructor - meaning it either came in null, was de-allocated later, or there is an ambiguity problem where there may be two defined and spring will pass in the first one created even though there may eventually be multiple executorServices created.
As this should be a valid bean definition as long as the class is included in your configuration's component scan, you may need to define the bean explicitly in a configuration class, especially if you have multiple beans of each type (which could also be your problem)
Ex:
#Configuration
class SomeConfiguration {
#Bean
public IngestionService myIngestionServiceDefaultBeanNameChangeMe(TransactionTemplate transactionTemplateParamSentBySpringAutomaticallyChangeMyName, AsyncTaskExecutor executorServiceSentBySpringAutomaticallyChangeMyName) {
return new IngestionService(transactionTemplateParamSentBySpringAutomaticallyChangeMyName, executorServiceSentBySpringAutomaticallyChangeMyName);
}
}
Note that for the configuration, the params for the bean method will be sent in by spring automatically once those beans have been initialized within this config or another config. Pretty cool eh?
Also the name of your bean corresponds with the method name here, and if you have multiple beans of the same type spring could pass in as parameters, you may need to tell spring which bean name to use. To do this you'd utilize the #Qualifier annotation.
I really hope this helps, or at least validate instantiation is happening correctly.

jmockit verifications block throwing Missing 1 invocation to methodName

Am trying to run one test case which will update the data into DB. This is my source code of test method.
#Tested // This is class-level scope as I have different test methods.
FirstLevelClass firstLevelClass;
#Test
public void testUpdateDB(#Mocked SecondLevelClass secondLevelClass) throws Exception {
// Updated method by passing an argument.
firstLevelClass.updateDatabaseThroughSecondLevelClass(info);
new Verifications() {{
SecondLevelClass.updateDB(creds, data);
times =1;
}};
Here my intention is to verify the expected invocations to mocked methods[which recorded in expectations]. But, verifications block is giving the following exception message. If I remove times=1, then test case is getting success. That is not my desired result.Can anyone please suggest me what could be wrong in my test case.
mockit.internal.MissingInvocation: Missing 1 invocation to:
SecondLevelClass#updateDB(creds, data)
with arguments: creds, data
Caused by: Missing invocations
Updated Question :
There is one argument to updateDatabaseThroughSecondLevelClass(info), from that argument we are forming creds reference in SecondLevelClass.
Credentials creds = info.getCredentials();
But in verifications block[Which is part of FirstLevelClass] we have created locally test object.
Credentials creds = getCredsTestObject();
This is the reason why it complained about Missing invocations. Because both are two different references in two classes. Can anyone please suggest me how to handle this case.
Thanks In Advance.
It is a known issue in the integration between TestNG and JMockit: https://github.com/jmockit/jmockit1/issues/337

Exception during PowerMock of HConnectionManager.class (HBase)

PowerMockito.mockStatic(HConnectionManager.class);
when(HConnectionManager.createConnection(configuration)).thenReturn(hConnection)
What are the ways to mock HBase related configuration files? As I get:
java.lang.ExceptionInInitializerError
at com.mapr.fs.ShimLoader.load(ShimLoader.java:214)
at org.apache.hadoop.conf.CoreDefaultProperties.<clinit>(CoreDefaultProperties.java:60)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:274)
at org.apache.hadoop.conf.Configuration.getClassByNameOrNull(Configuration.java:1857)
at org.apache.hadoop.conf.Configuration.getProperties(Configuration.java:2072)
at org.apache.hadoop.conf.Configuration.loadResource(Configuration.java:2282)
at org.apache.hadoop.conf.Configuration.loadResources(Configuration.java:2234)
at org.apache.hadoop.conf.Configuration.getProps(Configuration.java:2151)
at org.apache.hadoop.conf.Configuration.get(Configuration.java:871)
at org.apache.hadoop.conf.Configuration.getTrimmed(Configuration.java:890)
at org.apache.hadoop.conf.Configuration.getBoolean(Configuration.java:1291)
at org.apache.hadoop.hbase.HBaseConfiguration.checkDefaultsVersion(HBaseConfiguration.java:71)
at org.apache.hadoop.hbase.HBaseConfiguration.addHbaseResources(HBaseConfiguration.java:107)
at org.apache.hadoop.hbase.HBaseConfiguration.create(HBaseConfiguration.java:118)
at org.apache.hadoop.hbase.client.HConnectionManager.<clinit>(HConnectionManager.java:266)
at sun.reflect.GeneratedSerializationConstructorAccessor35.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
at org.powermock.api.mockito.repackaged.ClassImposterizer.createProxy(ClassImposterizer.java:143)
at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:58)
at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
at org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:46)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
at org.mockito.Mockito.mock(Mockito.java:1285)
at org.mockito.Mockito.mock(Mockito.java:1163)
Not a direct solution, but a reasonable workaround: I assume, you want to use PowerMock to test your code, that has to make this static call, to then use the result coming back from it.
So, instead of "directly" making this static call, you create a wrapper around this functionality, like:
interface ConnectionProvider {
public HConneciotn createConnection(configuration);
and a corresponding class that implements that method (by actually makes the static call).
Now you can change your other production code to work with your that new interface; and now, all your client code can be tested without the need to user PowerMokito ... because there is no more static call.
Of course, you might want to use PowerMokito to ensure that your new wrapper implementation is doing exactly what you expect it to do.
Use #SuppressStaticInitializationFor("org.apache.hadoop.conf.CoreDefaultProperties") to suppress static initialisation of the org.apache.hadoop.conf.CoreDefaultPropertiesclass. More information you may find in PowerMock documentation.
If you've just started write your application then, the better way will be create a class wrapper which will encapsulate static call and the wrapper in your system. There is a good principal: don't mock what you don't own.
And for the wrapper you may write an integration test that will test that wrapper works as you expected and you system expected.

playframework : NullpointerException when startup

I'm using Play 1.2.7, somehow I found my project become weird, when I start the application, and visit any valid URL, it shows an NullPointerException:
Oops: NullPointerException
An unexpected error occured caused by exception NullPointerException: null
play.exceptions.UnexpectedException: Unexpected Error
at play.Play.start(Play.java:563)
at play.Play.detectChanges(Play.java:637)
at play.Invoker$Invocation.init(Invoker.java:198)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.NullPointerException
at play.classloading.ApplicationCompiler$2.acceptResult(ApplicationCompiler.java:266)
at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:478)
at play.classloading.ApplicationCompiler.compile(ApplicationCompiler.java:282)
at play.classloading.ApplicationClassloader.getAllClasses(ApplicationClassloader.java:426)
at play.Play.start(Play.java:523)
... 3 more
And then I try to refresh the page, 2 or 3 time later, it become normal. What's going on here?
play doesn't support the following format in one class
public class A{
------
}
class B{
--
}
so make two different class instead of putting both in single class or use nested class.
It is a known bug: http://play.lighthouseapp.com/projects/57987/tickets/1379-unexpectedexception .
Maybe you use nested classes and Play has problems with it.

Error received using easymock

I am working on a new project and they have been using EasyMock (v2.4), which I am not as familiar with. I need to be able to do the following, but no one has an answer. The current framework uses an BaseDao.class which I would like to mock out per the following example, but I get an error. I'm looking for some direction.
BaseDao baseDao = EasyMock.mock(BaseDao.class);
EasyMock.expect(baseDao.findByNamedQuery("abc.query"), EasyMock.anyLong()).andReturn(...);
EasyMock.replay(baseDao);
EasyMock.expect(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong).andReturn(..);
EasyMock.replay(baseDao);
The error I'm getting is as follows...
java.lang.AssertionError:
Unexpected method call findByNamedQuery("def.query"):
findByNamedQuery("abc.query", 1): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)
at $Proxy5.findByNamedQuery(Unknown Source)
You are defining a replay(...) twice so only the first one will count. It's defined like this until you call reset(...).
To fix the problem, you can either:
1) Remove the invocation that is causing the test failure:
EasyMock.expecting(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong)
.andReturn(...);
EasyMock.replay(baseDao);
2) Instead of defining a fixed string in your expectation, you can expect any string:
EasyMock.expecting(baseDao.findByNamedQuery((String)EasyMock.anyObject()),
EasyMock.anyLong).andReturn(...);
It looks like the test expected a method call with the parameter "abc.query" but the method was called with "def.query" instead.
Debugging the test step by step should help finding the problem.
If you are expecting findByNamedQuery to be called twice, then remove the 1st call to the replay method. It is only needed the once, after all you expectations for the test have been set.
BaseDao baseDao = EasyMock.mock(BaseDao.class);
EasyMock.expect(baseDao.findByNamedQuery("abc.query"), EasyMock.anyLong()).andReturn(...);
// Remove EasyMock.replay(baseDao);
EasyMock.expect(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong).andReturn(..);
EasyMock.replay(baseDao);

Categories

Resources