Lambda - ClassNotFoundException - java

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.

Related

NullPointerException in async action when converting from Play 2.4 to Play 2.5

I'm porting a Play 2.4 project to Play 2.5(.18). I'm running into a spurious NullPointerException I cannot find the reason for. This is the stack trace:
! #76g5ina3j - Internal server error, for (POST) [/.../tokens] ->
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: java.lang.NullPointerException]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
Caused by: java.util.concurrent.CompletionException: java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:604)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:443)
Caused by: java.lang.NullPointerException: null
at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:350)
at akka.stream.scaladsl.Source.runWith(Source.scala:81)
at akka.stream.javadsl.Source.runWith(Source.scala:528)
at akka.stream.javadsl.Source.runFold(Source.scala:539)
at play.http.HttpEntity.consumeData(HttpEntity.java:58)
As you see, the stack trace does not feature any reference to code lines in my program, only the framework is mentioned. I already traced the best I could. The Play action is implemented asynchronously using CompletableFuture with supplyAsync and several thenApply() stages. A helper class finally assembles the Result by calling
return Controller.status(some_resultcode);
The ultimate NPE cause starts in HttpEntity.consumeData() and ends deep in the Scala parts of Play and in the Akka framework. That RunnableGraph.run() method reads
def run()(implicit materializer: Materializer): Mat = materializer.materialize(this)
While this definitely exceeds my Scala knowledge by several magnitudes, my conclusion is that the only null thing here can be that mystique materializer, whatever it might be. Where does it come from? What is it good for? How can it be null?
I tried to reproduce the problem with a much, much simpler action:
public CompletionStage<Result> version() {
return CompletableFuture
.supplyAsync(()->"2")
.thenApplyAsync(version->ok("Server v"+version));
}
Unfortunately, this action runs through without problems, so I do not have a simplified tesimonial of the problem so far.
I'm a bit lost currently. Can anyone explain to me what is going on and how to solve the problem?
Ok, found this one. Things were a bit different after deeper investigation. Actually, the action itself was not the problem. The Controller looked like this:
#With(OurLogger.class)
public class OurController extends Controller {
public CompletionStage<Result> ourAction() {
return CompletableFuture.supplyAsync(()->...);
}
}
The problem was the wrapping OurLogger. It featured this:
public class OurLogger extends Action.Simple {
private Result logResult(Result result) {
System.err.println("Result body: "+
JavaResultExtractor.getBody(result,1,null).utf8String());
}
public CompletionStage<Result> call(Context ctx) {
return delegate.call(ctx)
.thenApplyAsync(answer->logResult(answer));
}
}
The problem was the call to JavaResultExtractor.getBody(). In Play 2.4, it only gets two parameters. Play 2.5 added a third one - this mysterious Materializer which codifies some Akka piping concepts, as far as I understood it. While making the code compileable in Play 2.5, a colleague just added null as third parameter - and exactly that null was it about which the Akka code deep inside the framework stumbled later upon.
The solution was in the answers section of How to extract result content from play.mvc.Result object in play application? and lead to the following change of OurLogger:
public class OurLogger extends Action.Simple {
#Inject Materializer materializer;
private Result logResult(Result result) {
System.err.println("Result body: "+
JavaResultExtractor.getBody(result,1,materializer).utf8String());
}
// call() method unchanged
}
I would have found the problem much much faster if (a) the Play migration docs had mentioned this Materializer stuff and/or (b) there had only been the slightest hint of this getBody() call in the error stack trace in the first place. So it was two days of needle-in-haystack search...

Right exception to throw for the lack of a system property

Say I have a system property MY_PROP:
java -DMY_PROP="My value"
This property is necessary for my system to work.
What is the right exception to throw if this property is not set?
#PostConstruct
private void init() {
myProp = System.getProperty("MY_PROP");
if (myProp == null) {
throw new ????
}
// ...
}
Somehow IllegalArgumentException does not feel right. Maybe IllegalStateException, MissingResourceException, TypeNotPresentException? What is the standard practice for this scenario?
There is none. I would throw the IllegalStateException, because you are missing the parameter. This mean that configuration validator has failed and your application is in invalid state. In other words you should never be able to call the init() at all.
In case the value of parameter would be invalid, then i would throw an IllegalArgumentException.
If you are writing a validator, you should decide between using RuntimeException or checked one. When using for example javax.naming.ConfigurationException`, or created own one configuration exception. You API will be able to handle such exception and react properly in term of legacy.
Definitions:
IllegalStateException - Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
IllegalArgumentException - Thrown to indicate that a method has been passed an illegal or inappropriate argument.
I only add to Vash's answer for the Spring Framework. If your using the Spring Framework and you want to be consistent with how most of the components in Spring do it then I would say you should use IllegalStateException (or your own derivation).
In Spring most components that do a #PostConstruct or #Override void afterPropertiesSet() throw IllegalStateException using the util org.springframework.util.Assert.state(..).
You can see this done in Spring AMQP as one example.
That being said I have actually filed bugs against Spring MVC where they used IllegalArgumentException instead of a custom and more explicit derived class. With static inline classes its very easy to create a custom exception with out creating another Java file.
Because a system property is not always defined, the standard pratice is to use a default value when you can't find the property.
I just checked some standard code in java 7 (apache tomcat, java.lang, java.awt, ...), they always use a default "fallback" when the property is null.
So maybe your problem is somewhere else ?
Why don't you take this parameters as a required argument of your jar ? Then you can use IllegalArgumentException.

AutoCloseable "resource leak" warning for factory created instances?

These "resource leak" warnings I'm getting in Eclipse for AutoCloseables seem to be a life-saver.
However, how do I get them to work for factory created instances?
For example (a works, but b doesn't):
public static void main(String[] args) {
// a) This emits a warning
new AutoCloseable() {
#Override
public void close() throws Exception {}
};
// b) But this doesn't!
newResource();
}
public static AutoCloseable newResource() {
return new AutoCloseable() {
#Override
public void close() throws Exception {}
};
}
Is there an annotation I can stick on newResource() or something I can do to let the compiler (or is it Eclipse?) know of the ownership change?
The Neon Eclipse documentation on "resource leak" detection explains what is going on; see "avoiding resource leaks". It states:
Ownership / responsibility
The above diagnostics basically assume that a method that creates an
instance of a resource type is also responsible for closing this
resource. However, some resources will be shared among several
methods. Here the analysis makes the following assumptions:
If a method returns a resource to its caller, it is not responsible for closing; no problem is reported.
If a resource is stored in a field, no single method is considered as responsible for closing; no problem is reported.
If a method obtains a resource via a method call rather than by a new expression, it may or may not be responsible; any problems are
only flagged as potential resource leaks.
If a resource is passed as an argument in a method call or constructor call, the current method may or may not be responsible;
any problems are only flagged as potential resource leaks.
Point #1 explains why there is no "resource leak" warning for the return statement in the newResource method.
Point #3 explains why there is no "resource leak" warning for the newResource() call. At best, it would be a "potential resource leak" warning. Either you have those warnings disabled, or the previous warning is inhibiting it.
Q: Is there an annotation to tell Eclipse about transfer of resource ownership?
A: The Neon Eclipse documentation doesn't mention any such annotation. (And it does go into detail about the annotations for null checking!)

Strange Guice injection error

I have a very strange error when trying to inject with constructor with Guice. There is a particular line in the constructor as the following:
#Inject
public RoundRobinAssigner(
... arguments
) {
...stuff
assignments = Sets.synchronizedNavigableSet(Sets.<CountingEntry<String>>newTreeSet());
}
This fails upon injection with the following.
1) Error injecting constructor, java.lang.NoSuchMethodError: com.google.common.collect.Sets.synchronizedNavigableSet(Ljava/util/NavigableSet;)Ljava/util/NavigableSet;
at edu.harvard.econcs.turkserver.util.RoundRobinAssigner.<init>(RoundRobinAssigner.java:46)
at edu.harvard.econcs.turkserver.util.RoundRobinAssigner.class(RoundRobinAssigner.java:40)
while locating edu.harvard.econcs.turkserver.util.RoundRobinAssigner
But if I remove the Sets.synchronizedNavigableSet() wrapping, things inject just fine.
#Inject
public RoundRobinAssigner(
... arguments
) {
...stuff
assignments = Sets.<CountingEntry<String>>newTreeSet();
}
Clearly, this is suboptimal as I want to use the synchronized set. Is there any reason why a Guice-called instructor would behave any differently than a normal one? Neither of these code has any compile problems and the Sets class from guava has too have been loaded, so I have no idea what is causing this.
I suspect you're just seeing a problem which you'd otherwise see elsewhere - basically because Guice is involved when loading up the class via reflection, the "link time" error of Sets.synchronizedNavigableSet being unavailable is shown within the context of Guice instead of in a "normal" constructor call.
synchronizedNavigableSet was only introduced in 13.0 - is it possible that you're compiling against that, but running against an older version of Guava?

ApplicationError when trying to implement an edited version of the Secure module

I'm implementing an edited version of the Secure controller, default in the latest Play Framework.
I have read several times that, if you want to customize the Secure behaviour, you're better off copying the source of the Secure module, and start customizing it.
So I did, and after editing the needed dependencies I received following error:
Execution exception
NullPointerException occured : null
In /app/controllers/SecureController.java (around line 194)
190:
security = classes.get(0);
191:
}
192:
if(security==null)System.out.println("security is null");
193:
try {
194:
return Java.invokeStaticOrParent(security, m, args);
195:
} catch(InvocationTargetException e) {
196:
throw e.getTargetException();
197:
}
198:
}
199:
200:
}
The first logic conclusion to jump to is: there are no classes that implement the needed Secure$Security inner class. But there most certainly is a subclass, so I was wondering how this error can be fixed.
A debugging session learns that the classes.get(0) does contain the class that has the #With annotation. So the null pointer exception must be caused by something within the class that contains the #With(SecureController). But I left that class just the way it was, I just edited the reference within the With annotation.
So my guess is that somehow, there is a null pointer within the class implementation.
But even when I implement default behaviour, without any references, it still generates a nullpointerexception.
EDIT:
I found the cause of this error, but the 'why' isn't clear.
This line is found in the implementation of the authenticate(...) method in the subclass of SecureController$Security:
flash.put("url", request.url);
Why does this fail?
I understand this situation may be very hard to reproduce, but I was wondering if someone already experienced the same issue.
Thanks for the help (on many Play! related topics) so far.
the Scope.Flash class does not allow you to store null values. Perhaps you unset or failed to set request.url elsewhere in your modifications?

Categories

Resources