Hi everyone I have the following code trying to use CDI's #produces
import java.sql.Connection;
import javax.enterprise.inject.Produces;
public class ConnectionSupplier
{
#Produces
//#RequestScoped
#Connect
public Connection getConnection()
{
//get connection from datasource
}
}
And this is #connect Qualifier
//remove imports
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD})
public #interface Connect{}
and here we make injection
import com.seta.history.db.entities.Day;
import java.sql.Connection;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
#RequestScoped
#Named("day")
public class DayController
{
#Inject
#Connect
private Connection connection;
public void save(Day day)
{
//do-save
}
}
but it gives the following exception
Severe: Exception during lifecycle processing
org.glassfish.deployment.common.DeploymentException: CDI deployment
failure:WELD-001408: Unsatisfied dependencies for type Connection with
qualifiers #Connect
at injection point [BackedAnnotatedField] #Inject #Connect private
com.seta.history.db.controllers.DayController.connection
at
com.seta.history.db.controllers.
DayController.connection(DayController.java:0)
I am using Java EE 7 + GlassFish 4.1.2
NOTE we usually used Glassfish and CDI and it works fine
so can anyone help And thanks in advance
In CDI > 1.0, if you do not have any beans.xml, CDI only scans annotated classes. So CDI does not take into account your ConnectionSupplier class and the producer.
You have two ways to correct this :
Annotate your ConnectionSupplier class (for example with #ApplicationScoped)
Add a beans.xml with bean-discovery-mode="all" to tell CDI to scan all classes.
Related
I'm following https://www.baeldung.com/spring-webflux-errors tutorial to handle errors in Spring Webflux project.
package com.example.demo.exception;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
import java.util.Map;
#Component
#Order(-2)
public class ExceptionWebHandler extends AbstractErrorWebExceptionHandler {
public ExceptionWebHandler(ErrorAttributes errorAttributes,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
super(errorAttributes, new ResourceProperties(), applicationContext);
super.setMessageWriters(serverCodecConfigurer.getWriters());
super.setMessageReaders(serverCodecConfigurer.getReaders());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {
Map<String,Object> errorAttributes = getErrorAttributes(serverRequest, false);
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(errorAttributes.get("message")));
}
}
I'm getting the following error when running the project.
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.web.reactive.error.ErrorAttributes' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Description:
Parameter 0 of constructor in com.example.demo.exception.ExceptionWebHandler required a bean of type 'org.springframework.boot.web.reactive.error.ErrorAttributes' that could not be found.
The following candidates were found but could not be injected:
- Bean method 'errorAttributes' in 'ErrorWebFluxAutoConfiguration' not loaded because not a reactive web application
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.web.reactive.error.ErrorAttributes' in your configuration.
I'm not sure which object should I autowire. The error message says its for ErrorAttributes, but I dont know how. I tried adding #Autowired to the parameter in the constructor and separately as a property of the class, but it didn't help.
The following candidates were found but could not be injected: - Bean method 'errorAttributes' in 'ErrorWebFluxAutoConfiguration' not loaded because not a reactive web application
is probably your problem or at least one of the problems.
The Spring documentation states in the last paragraph:
Adding both spring-boot-starter-web and spring-boot-starter-webflux modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux. This behavior has been chosen because many Spring developers add spring-boot-starter-webflux to their Spring MVC application to use the reactive WebClient. You can still enforce your choice by setting the chosen application type to SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).
So somewhere in your application you are pulling in spring-web either directly or transitively through some other dependency.
This in turn will result in that your application will automatically be configured as a non-webflux application.
im little confused. What is the exact difference between javax.inject.Singleton and javax.ejb.Singleton?
I found a plausible explanation here:
By default, javax.ejb.Singleton session beans are transactional (section 13.3.7 of the EJB 3.1 specification) and require acquisition of an exclusive lock for every business method invocation (sections 4.8.5.4 and 4.8.5.5).
In contrast, a javax.inject.Singleton is not transactional and does not support container-managed concurrency (the major consequence being that no locking scheme is implemented by the container). [...]
If you don't need EJB features, stick with #ApplicationScoped (javax.inject.Singleton is not defined by CDI, and its semantics are therefore not governed by that specification).
To reduce future confusion, I use this small unit test (first level package name needs to be replaced):
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.junit.Test;
public class SingletonTest {
/** requires com.tngtech.archunit:archunit-junit:0.4.0 */
#Test
public void detectWrongSingletonAnnotation() {
final ClassFileImporter importer = new ClassFileImporter();
final JavaClasses classes = importer.importPackages("first_level_package");
noClasses().should().beAnnotatedWith("javax.inject.Singleton")
.as("Please use javax.ejb.Singleton instead of javax.inject.Singleton.")
.check(classes);
}
}
Since accepted answer didn't solve my problem I post my own answer. It won't be as good as article by Adam Bien but definitely will be more practical:
Consider following code:
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
#Singleton
public class DatabaseConnection {
#PostConstruct
public void init() {
System.out.println("init");
}
public ChampionComp getFirstRecord() {
return new ChampionComp("Ashe", "Teemo", "Warwick",
"Blitzcrank", "Syndra", "Anivia", "Brand", "Rammus", "Xin Zhao", "Irelia");
}
}
And this REST service:
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
#Path("/champions")
public class ChampionsAPI {
#Inject
private DatabaseConnection db;
#GET
#Produces("text/plain")
public String getClichedMessage() {
ChampionComp comp = db.getFirstRecord();
return comp.toString();
}
}
Using javax.ejb.Singleton this code works just fine. The DatabaseConnection instance is created once and injected to REST service.
However when replacing ejb in import with inject you would receive NPE in ChampionsAPI class while accessing db field - that's because your Singleton was not created (for some reason, maybe because one need to make use of interfaces while using javax.inject.Singleton ? ).
In simple clarity:
javax.ejb.Singleton is an annotation used to create an #Singleton EJB (as opposed to #Sateless EJB or #Stateful EJB)
On the other hand, javax.inject.Singleton is an annotation used to create a CDI with singleton scope
So basically, one creates a singleton EJB while the other creates a CDI with singleton scope
I am trying to do something at startup using a startup ejb. But my bean is never called.
This is my bean:
import javax.annotation.PostConstruct;
import javax.ejb.Startup;
import javax.inject.Singleton;
#Singleton
#Startup
public class StartupBean {
#PostConstruct
public void doSomething(){
System.out.println("why??");
}
}
I am using jboss 7.1.1.
What am i doing wrong? You can find my source code at bitbucket: https://bitbucket.org/cremersstijn/jee/src/9e22ed2b798a/simple-startup-bean
You're importing the wrong Singleton. If you want to create a singleton session bean, use javax.ejb.Singleton.
http://docs.oracle.com/javaee/6/api/javax/ejb/Singleton.html
vs.
http://docs.oracle.com/javaee/6/api/javax/inject/Singleton.html
I have a spring bean that I have configured in applicationContext like below:
<bean id="beanIRPlus" class="org.jadefalcon.demo.server.Spring.beans.BeanIRPlus" />
Then I have a Hibernate Service like below that I am trying to inject into the Spring bean. Normally, for example, if I use a prototype bean thats injected into my controller and that has an injected Hibernate service it works fine, however for this particular bean it is a singleton so its created when the application starts up. I made sure to even put the bean declaration at the very end of the applicationContext.xml file figuring maybe it has to be put after anything Hibernate related but the issue is still persisting. Its giving a null pointer exception, that the CasesService object doesn't exist. Any advice on what I'm doing wrong is greatly appreciated:
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.jadefalcon.demo.domain.Cases;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service("casesservice")
#Transactional
public class CasesService {
protected static Logger logger = Logger.getLogger("service");
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
public void add(Cases cases) {
logger.debug("Saving new search");
// Retrieve session from Hibernate
Session session = sessionFactory.getCurrentSession();
// Save
session.save(cases);
}
}
I didn't see how you are trying to inject it. You have at least two options:
xml. Define a <property name=".." ref="casesservice"> in your controller bean definition
annotations. Use #Autowired private CaseService service (or #Inject)
Similar to How can I access the ServletContext from within a JAX-WS web service?, is there a way to access applicationContext, easier than this?
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.servlet.ServletContext;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
#WebService
public class MyWebService {
// boilerplate code begins :(
#Resource
private WebServiceContext context;
private WebApplicationContext webApplicationContext = null;
/**
* #return
* #throws IllegalStateException
*/
private WebApplicationContext getWebApplicationContext()
throws IllegalStateException {
if (webApplicationContext != null)
return webApplicationContext;
ServletContext servletContext =
(ServletContext) context.getMessageContext().get(
MessageContext.SERVLET_CONTEXT);
webApplicationContext =
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
return webApplicationContext;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
#WebService(
endpointInterface = "Bla",
targetNamespace = "http://bla/v001",
wsdlLocation = "WEB-INF/wsdl/bla.wsdl",
serviceName = "BlaService",
portName = "BlaPort")
public class BlaWs extends SpringBeanAutowiringSupport implements BlaPort {
#Autowired
#Qualifier("dao")
private Dao dao;
...
}
I don't think that the web service should have to know about web or servlet contexts or its application context. I don't see why it should have to know any of that. Shouldn't it be far more passive? Inject what it needs and let it do its work. The service interactions with a client should be based on a contract defined up front. If it has to get unknown values from a context of some kind, how will clients know what needs to be set or how to set it?
I'd go further and say that a web service should be a wrapper for a Spring service interface. It's just one more choice among all the possible ways to expose it. Your web service should do little more than marshal and unmarshal the XML request/response objects and collaborate with Spring services.
Make your web service bean extend a spring bean.
like this
I would install a Filter that saves ServletContext before chaining in a ThreadLocal
According to the JavaDoc for the SpringBeanAutowiringSupport class, see:
http://docs.spring.io/autorepo/docs/spring-framework/3.0.x/api/org/springframework/web/context/support/SpringBeanAutowiringSupport.html
Read the NOTE: at the end of the javadoc.
The original question, may in fact, be the way that this should be implemented.