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?
Related
On my current project, I've felt the need to create a sort of simulated callback system in Java using reflection. However, I'm having issues getting my reflection to actually function. The code at fault follows:
public Callback(Object parentObj, String methodName, Class<?>...parameters)
{
if(parentObj == null)
throw new IllegalArgumentException("parentObj cannot be null", new NullPointerException());
Class<?> clazz = parentObj.getClass();
// Trace debugging, see output
for(Method m : clazz.getDeclaredMethods())
if(m.getName().equals("myMethod")) System.out.println (m);
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); } // Exception caught
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
When I construct the Callback object, I'm using syntax like this:
new Callback(this, "myMethod", boolean.class)
When I try to create my pseudo-callback, it hits the NoSuchMethodException catch block. I've included some trace debugging above to show the output of one of my methods failing. The output:
private void my.package.MyClass.myMethod(boolean)
java.lang.NoSuchMethodException: my.package.MyClass.myMethod(boolean)
at java.lang.Class.getMethod(Class.java:1605)
at my.package.other.Callback.<init>(Callback.java:63)
I couldn't figure the problem out, so I started hunting, to little avail. The best I could find was mention of versioning conflict between the compiled JAR and the runtime. However, MyJar.jar/META-INF/MANIFEST.MF contains Created-By: 1.6.0_02 (Sun Microsystems Inc.). My IDE is running C:\Program Files\Java\jdk1.6.0_02\bin\javac.exe to compile my project. I'm using C:\Program Files\Java\jdk1.6.0_02\bin\java.exe to run my JAR.
I'm at a loss why Class.getMethod is claiming the method doesn't exist, but Class.getMethods seems to have no problem finding it. Help? :(
Your method is private but getMethod() only returns public method.
You need to use getDeclaredMethod().
You need the parameter list to be absolutely correct for the method you want for the call to succeed.
I've found that tiny steps are important when doing reflection because the compiler doesn't help. Write a small snippet which actually invokes exactly the method you want to in this particular case, and then when that works, generalize it into the framework here. I would focus on the parameters passed.
The Javadoc for getMethod isn't explicit, but it looks like it might throw a NoSuchMethodException for methods that aren't public, and your method is private.
The versioning issue that can cause NoSuchMethodException isn't a difference between the compiler versions. It's a difference in the version of (in your case) MyClass at compile time versus runtime.
Since you're using reflection you issue might have nothing to do with versioning, though. Certainly that would not explain different behavior between getMethod and getDeclaredMethods, because you're running them against the same Class instance, hence a version difference isn't really possible.
Are you sure that the parameters match your actual method?
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.
It's the first time I have to use Dependency Injection and I'm a little confused.
I don't really understand how it works.
I have tried on a simple example :
public class StockResponse extends Response
{
#Inject BrandService $brand;
public List<StockResponseItem> stock;
public StockThresholdResponse()
{
stock = new ArrayList<>();
}
public static StockThresholdResponse create(List<DataItem> data)
{
StockResponse stock= new StockResponse();
for (ThresholdCheckAggregate data: d)
{
StockResponseItem item = new StockResponseItem();
item.id = d.thresholdId;
item.brand = str.$brand.byId(d.brand);
str.stockThresholds.add(item);
}
return str;
}
}
But when I use my create() method, I get a null pointer exception for $brand.
I think I have misunderstood how DI works but I can't find my error.
I had similar difficulties to understand how DI (Guice out of Java EE) works. In simple words Guice must have chance to modify You object, for example:
assist by construction usually.
You ask Guice "can You create my object" injector.getInstance(cls), then Guice is creating object for You, solving field or constructor annotation
In normal (non Java EE) environment Yoy never call classic constructor, You ask by second hand.
other method.
Few library / frameworks have integration with Guice (Apache Wicket I personally like) with "creation listeners" on some types of objects. Hard work of DI is hidden for Your eyes, but is executed.
Java EE lets say better EE programmers than me :(
In consequence Yoy don't give chance to inject anything, is null
Professionals sorry that I say at blondie level. That is way like I discovered DI few years ago
Correction to code. Not
StockResponse stock= new StockResponse();
but
mod = .... // Module
injector = Guice.createInjector(mod); // global or almost global
...
injector.getInstance(StockResponse.class);
EDIT: intentionally I don't answer "how to write Guice module", assume this is other, long story
This could work, assuming BrandService is either a concrete class or if it's an interface, you have provided a binding for it to a concrete class elsewhere in your DI configuration (say a module in Guice or Spring #Configuration). I do see one obvious NullPointerException with str variable. Did you mean to do this?
item.brand = stock.$brand.byId(d.brand);
I am getting this error:
Exception in thread "Thread-0" java.lang.VerifyError: Constructor must call super() or this() before return in method JGame.Util.KeyboardMap.<init>()V at offset 0
at JGame.Room.Room.keyboardEventTests(Room.java:81)
at JGame.Room.Room.run(Room.java:54)
at java.lang.Thread.run(Thread.java:722)
When my application loads, it calls this method right away (KeyboardMap.map is an empty HashMap).
Here is the Method (Line 54 calls this method this.keyboardEventTests();):
protected void keyboardEventTests(){
for(Map.Entry ap : KeyboardMap.map.entrySet()){ // Line 81
Mapping mp = (Mapping)ap.getValue();
if(mp.doing){
mp.run();
}
}
}
And here is the KeyboardMap class.
package JGame.Util;
import java.util.HashMap;
import java.util.Map;
public class KeyboardMap{
public static Map<String, Mapping> map = new HashMap<>();
public static void set(String key, Boolean value, Runnable run){
Mapping mp = new Mapping();
mp.doing = value;
mp.run = run;
KeyboardMap.map.put(key, mp);
}
public static Mapping get(String key){
return KeyboardMap.map.get(key);
}
}
Why am I getting that error, and how can I get rid of it?
Why am I getting that error, and how can I get rid of it?
The big clue is that this is a VerifyError, not a compilation error. What this means is that the JVM has found a bytecode file in which one of the constructors is not chaining properly. These are (in effect) a malformed bytecodes.
How can that happen?
Well it CAN'T happen in a Java class that is (just) compiled in the normal way. The compiler will automatically insert an implicit super() call into any constructor that doesn't explicitly chain.
If this is Java code, then either:
the class was compiled using broken compiler (unlikely!), or
something has tweaked the bytecodes after compilation.
If it was some other language, then the first suspect would be the "other language to bytecode" compilation process.
I think you are getting this problem because your unit tests is using a mocking framework, and the mocking framework is using "byte code engineering" to inject something into the classes under test. The code that is doing this has "made a mistake" and the result is bytecodes that won't compile.
This was apparently fixed by a rebuild, but that doesn't contradict this explanation. A rebuild could clear out broken instrumentation code injected by the mocking framework. And next time around, the framework could "get it right".
Just override the default contructor by adding
public KeyboardMap() {
}
to the KeyboardMap class. It will work.
I had the same problem, and it was caused by a very strange thing:
In NetBeans, i use editor fold to fold long codes:
// <editor-fold desc="SOME DESCRIPTION">
...
...
// </editor-fold>
And it appeared that in one of such my folds i had forgotten to write the beginning of fold, like this:
...
...
// </editor-fold>
Correcting this solved my problem.
Strange, because this is just a comment and it's for NetBeans
In my case, turning off minify in build.gradle under buildTypes helped.
minifyEnabled false
Scenario
2x same Interceptor in same EJB on 2 methods:
...
#Interceptors(PerformanceAuditor.class)
public Date refreshIfNecessary() {
// there is also the PerformanceAuditor-Interceptor on this method
Pair<Date,String> lastImportDate = importDbDAO.findLatestImportLog();
someContainer.reloadIfNecessary(lastImportDate);
return lastImportDate.getLeft();
}
#Interceptors(PerformanceAuditor.class)
public boolean checkAndRefreshIfNecessary(final Date importDate) {
Date lastImportDate = refreshIfNecessary();
return lastImportDate.after(importDate);
}
...
Now we call on this EJB the methods externally with the following outcome:
calling refreshIfNecessary() -> PerformanceAuditor is called 2 times
calling checkAndRefreshIfNecessary() -> PerformanceAuditor is called also 2 times!
(but expected 3 times since one nesting level more!)
So what's happening here?
The answer is simple:
Interceptors "trigger" only if called as an "EJB call" (i.e. via their EJB interface). But in checkAndRefreshIfNecessary() the call of checkAndRefreshIfNecessary() is a simple Java method call and therefor not noticed by the container.
Solution: To call a method in an EJB internally as EJB call you have to go via its Interface which can be accessed e.g. via injected SessionContext and then via
context.getEJBLocalObject()... But this is certainly no a pretty solution! Better rethink your design in such cases!
PS: That's a beautiful example that one has still to understand the internals of an application server. Unfortunately from EJB3 onwards most features are so easy to use that more and more developers will not be confronted with the internals which will lead more often to such errors or at least bad design...