Glassfish 4 scans for #PostConstruct with CDI disabled - java

I'm doing and upgrade from Glassfish 3.1.2.2 to Glassfish 4.1 for a set of Spring applications. Since I use the Spring to handle #Inject annotations, I have disabled Glassfish' CDI using this command:
asadmin set configs.config.server-config.cdi-service.enable-implicit-cdi=false
Still, when I deploy one of my applications, I get the following error message:
The lifecycle method [something] must not throw a checked exception.
Related annotation information: annotation [#javax.annotation.PostConstruct()]
on annotated element [public void com.something.MyClass.something() throws
java.io.IOException] of type [METHOD]. Please see server.log for more details.
The class in question is an abstract class with no implementations in the application that I'm trying to deploy, it's just something that is on my classpath.
Why is Glassfish validating my #PostConstruct when I've disabled CDI? Why is Glassfish validating #PostConstruct on something that can not become a bean?
How can I prevent Glassfish from interferring with anything that I'm using Spring for?

Annotation #PostConstruct is a general annotation used in any dependency injection mechanism. The Javadoc explicitely states that, unless used within an interceptor, it must be put on a method, which has void return type and throws no checked exceptions.
It is weird that Spring allows checked exceptions on post-construct methods, as there is not way how to handle them. But as this requirement is only a validation and can be ignored, Spring probably ignores checked exceptions and Glassfish does not. There is possibly an unnecessary Glassfish feature, that it scans and validates all classes, even if not used in CDI or any other mechanism (EJB, ...)
The best is to remove checked exceptions to align the code with the documentation and make it portable.

You can solve this issue first by adding a web.xml with metadata-complete="true". Next you will want to make sure your context are in the Web root Directory /WEB-INF/.
With this glassfish can load all #PostConstructSpring dependencies.
More of a work around in my opinion.

Related

Disable WARN logging from AbstractHandlerExceptionResolver in Spring

Below exception handler that is common for all my controllers, is working fine except that I need to disable the WARN log from AbstractHandlerExceptionResolver class after processing the exception. Using Spring Web MVC 5.x version.
#ControllerAdvice
public class AllExceptionHandler{
#ExceptionHandler(SomeCustomException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void exceptionHandler() {
}
}
This is the log that is generated which I'm trying to avoid:
02-20-2019 15:22:54,896 WARN [http-nio-8080-exec-1] (AbstractHandlerExceptionResolver.java:140) - Resolved [com.rasa.rrt.ste.controller.SomeCustomException]
I'm not using Spring Boot.
Tried to extend the above AllExceptionHandler class with ExceptionHandlerExceptionResolver and call warnLogCategory(null) in the AllExceptionHandler constructor, but it throws NullPointerException.
Also, I see on Google to set this property spring.mvc.log-resolved-exception=false to disable warning, but not sure where/how to set it.
You mentioned spring.mvc.log-resolved-exception=false as a possible solution:
Also, I see on google to set this property "spring.mvc.log-resolved-exception=false" to disable warning, but not sure where/how to set it.
The spring.mvc.log-resolved-exception property is a Spring Boot property, and would be set using standard Spring Boot externalized configuration mechanisms. Enabling the property causes Spring Boot to configure HandlerExceptionResolver beans to log exceptions when they otherwise wouldn't.
Whether to enable warn logging of exceptions resolved by a "HandlerExceptionResolver", except for "DefaultHandlerExceptionResolver".
Since you've stated you're not using Spring Boot, this property is not applicable to your scenario.
You can disable this warning log in your logback configuration,
by specifying in my case in 'logback-spring.groovy' following line
logger("org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver", ERROR)

How to add a EJB Interceptor programmatically?

I'm trying to add a Interceptor in a EJB at runtime programmatically via CDI extensions.
This EJB exposes a Remote interface for remote calls. But I'm trying to add this Interceptor in the implementation class of this EJB adding the #Interceptors annontation like in this other SO question (CDI Extensions - Add Interceptors in ProcessAnnotatedType phase)
I think the CDI Extension only executes after the EJB are already registered because the Interceptor is never called.
But, for test purpose I have successfully register and execute an Interceptor programmatically in a simple CDI Bean.
The problem is when I'm try to register in a EJB.
Am I missing something?
Edit:
I'm using Wildfly 8
I think the key problem here is the difference between #Interceptors (EJB ones) and #Interceptor (CDI ones). CDI does not govern EJB container hence adding the EJB annotation (#Interceptors) in CDI extension won't necessarrily kick EJB logic into effect - EJB container might have started at that moment and it won't know of the annotation. Furthermore the CDI extension would add this annotation to the AnnotatedType which is a structure EJB probably won't make use of. On the other hand, all this really depends on the application server as it is responsible for CDI/EJB integration hence as a "bonus" the behavior might differ between AS.
CDI extension is something which allows you to hook into CDI bootstrap lifecycle, therefore you are able to use/enable/add CDI interceptors. I would try going that way instead. BTW even the SO question you referred to speaks of beans.xml/#Priority for enablement which means it uses CDI interceptors and not EJB ones.
Also, an EJB bean should automatically become CDI bean therefore you can attach CDI interceptor to it without changing the bean itself.

exception while trying to deploy liferay portlet with spring

I'm trying to create a portlet with liferay 6.2 and using spring. If I create a bean without using constructor-arg or factory-method then everything works fine. But if I use either of these then I get exceptions when the portlet is deployed.
an example:
the exception I'm getting is:
01:28:21,884 ERROR [ContextLoader:323] Context initialization failed
java.lang.IncompatibleClassChangeError: class org.springframework.core.LocalVariableTableParameterNameDiscoverer$ParameterNameDiscoveringVisitor has interface org.springframework.asm.ClassVisitor as super class
I realize that this can be caused by having 2 versions of ams, but im using the spring jars that come with liferay.
You give an option yourself - duplicate classes. But without knowing how you build and what you're doing, there's hardly anything to do apart from asking you to make extra extra extra sure that you don't have duplicate resources on the classpath:
Check your deployed web application (once it's deployed to your application server) and its WEB-INF/lib folder for such duplicates. They might come in only during the buildprocess, e.g. they might not be in your IDE's workspace. Or Liferay might inject them (due to declared dependencies) during deployment.
You'll have to figure out how (and in which phase) those resources get there, then eliminate that option (e.g. through proper maven scope, e.g. "provided")

Persisting my first entity using Java EE

Trying to get my head around Java EE (ORM/Entities/Annotations/EJB/Servlets etc.). So I've created a very simple webpage where you can enter user information and send it to the server. I'm using Apache Tomcat 8.0 as webbserver application and here is all the relevant parts of the application files and content that is needed to persist an entity:
http://pastebin.com/fwfbnYpU
The application gives me the error on line 99 saying:
08-Apr-2014 16:18:10.329 SEVERE [http-nio-8084-exec-93] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [indexServlet] in context with path [/JavaEENackademin] threw exception
java.lang.NullPointerException
What am I doing wrong? The database exist with the correct named table and columnnames. But then again that is not the problem here maybe it will become a problem after I fix this problem :)
One issue with your code is that you should not inject EntityManagers into servlets. Servlets are usually singletons, so all servlets would use the same EntityManager. You should inject an EntityManagerFactory instead and get your EntityManagers from it. You also have to take care of transactions. Not sure if this has caused your issues, but something that should be fixed.
I'm surprised you are able to deploy the code in your pastebin. Especially:
#WebServlet(name = "indexServlet", urlPatterns = {"/indexServlet"})
public class indexServlet extends HttpServlet {
#Inject
LoginValidation validation;
#PersistenceContext(unitName = "JavaEENackademinPU")
private EntityManager em;
//... offending line 99 calls: em.persist()
}
Neither PersistenceContext nor Inject are part of the servlet spec, so you probably added additional jars to your installation.
But you configured your persistence.xml to use JTA transactions which are barely supported in a servlet environment, probably resulting in tomcat ignoring the #PersistenceContext annotation altogether and leaving em == null (the default value).
I've found this link describing an integration but it looks complicated, requires editing internal xml files and then goes on to use Spring. Likely every part of that is overkill for a beginner.
I suggest you start fresh with a copy of TomEE which already does all the wiring to get you a fully fledged application server that supports CDI (#Inject) and JPA (#PersistenceContext) out of the box.

How to get a 'JBoss service' with CDI in JMX with AS6?

I'm currently migrating a JBoss service class from AS5.1 to AS6 (not going to AS7 for a variety of reasons).
For AS5.1, the service implements a {serviceName}MBean and has a jboss-service.xml with attribute values. It's packaged in a jboss-sar, which is packaged in an EAR to be deployed. When deployed, the service fields are populated with the values from jboss-service.xml, and the service is automatically registered into JMX.
I would like to achieve the same thing using AS6, but would like the service to support CDI - so I'd like its new #Inject injection points to be satisfied. I need these to be satisfied in the object registered with JMX, so that methods called via JMX can reference injected fields, but I'm struggling to achieve this.
I've had to package the service in a jar, instead of a jboss-sar, for classloader reasons, but let's say it's otherwise unchanged. When deployed to AS6, all works as before - service goes into JMX, values from XML propagate to the object. However, the instance created does not have its CDI injection points satisfied, and neither does the object registered in JMX.
If I annotate the service class with #Startup and #javax.ejb.Singleton, but keep its interface and the jboss-service.xml, the object registered into JMX still does not have its CDI injection points satisfied. However if I programmattically deregister that bean, and re-register the instance in a #PostConstruct method, then the bean in JMX DOES have its injection points satisfied. However that bean no longer has the values specified in the jboss-service.xml.
So how can I get the best of both worlds? CDI and the usual JBoss service behaviour? What is the correct way to implement a JBoss service with CDI? I've been unable to find documentation on this. Hope someone can help.
Thanks,
Ben
As a worst-case fallback, you should be able to use the CDI extension API to get your service to be injected. I don't think you would need to write a fully-fledged extension, but if you have an initialisation hook in the service object, you can do this (lifted with minor editing from the docs, not compiled or tested):
public static <T> void inject(T object) {
BeanManager beanManager = (BeanManager)new InitialContext().lookup("java:comp/BeanManager");
AnnotatedType<T> type = beanManager.createAnnotatedType(object.getClass());
InjectionTarget<T> it = beanManager.createInjectionTarget(type);
CreationalContext ctx = beanManager.createCreationalContext(null);
it.inject(object, ctx);
it.postConstruct(object);
}
Basically, any object to that method will get injected. All the usual CDI annotations should work. Hopefully.
As mentioned in the comments above, it seems Tom's right - there's no 'nice' way of created a CDIed, JMX bean in one go, you either have to put your JMX bean in CDI, as is suggested above, or put you CDIed bean into JMX. We tried the former, but it appears the BeanManager isn't bound to JNDI at the point the service starts up.
So instead we went with CDI bean -> JMX. We're creating the services as Singleton EJBs, so their injection points are satisfied, and they then get registered/unregistered to JMX in their PostConstruct/PreDestroy methods, using German Escobar's excellent CDI portable extension (germanescobar.net/2010/01/cdi-portable-extension-jmx.html, community.jboss.org/thread/148750 is also helpful).
May try to use ApplicationScoped beans and get them to start by observing a ContainerInitialized(?) event, however, as we don't need all the features of an EJB. Haven't tried that yet, mind...

Categories