When trying to #Inject (javax.inject.Inject) to inject MyConfigurationService within #SlingServlet MyServlet leads to a NullPointerError anytime any operations are attempted on myConfigurationService within an AEM OSGi container using Maven org.apache.felix.maven-scr-plugin as part of the build process.
Service Implementation:
#Service({MyConfigurationService.class})
#Component(immediate = true, metatype = true, label = "My Configuration Service")
public class MyConfigurationServiceImpl implements MyConfigurationService {
#Property(unbounded = PropertyUnbounded.DEFAULT, label = "API URL", description = "API URL")
private static final String API_URL = "apiurl";
private String apiUrl;
#Activate
protected void activate(Map<String, Object> properties) {
this.apiUrl = PropertiesUtil.toString(properties.get(API_URL), "");
}
}
Servlet:
#SlingServlet(paths = "/bin/myServlet", methods = "POST", metatype = true)
public class MyServlet extends org.apache.sling.api.servlets.SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(MyServlet.class);
#Inject
MyConfigurationService myConfigurationService;
#Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServerException, IOException {
// any attempts to use myConfigurationService results in NPE
}
}
However using #Reference (org.apache.felix.scr.annotations.Reference) in place of #Inject successfully injects the service and is usable within the #SlingServlet methods such as doPost:
#Reference
MyConfigurationService myConfigurationService;
Why does #Inject fail to inject the service into the #SlingServlet when #Reference works?
Thank you for any help you can provide!
I think you are confusing the sling models #Inject with SCR annotations used by the maven SCR plugin.
The maven SCR plugin defines annotations to be processed at build time those are defined here: http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html
All those annotations are under the package org.apache.felix.scr.annotations
The #Reference annotation can only be used with #Component, #service, #SlingServlte or any other SCR class annotation that defines an OSGI component.
The javax.inject.Inject annotation is generic and is used by many frameworks for dependency injection. In AEM or Sling's case, it only means something inside a Sling Model (a class annotated by org.apache.sling.models.annotations.Model), read more about #Inject and other annotations that can be used in a Sling Model here: https://sling.apache.org/documentation/bundles/models.html#basic-usage
Related
Im using spring boot with modules. I have a parent project with several sub modules.
Camel Routes are failing to start up when I configure the route with Contructor Autowiring.
I get Total 0 routes, of which 0 are startedWhen starting constructor like this.
private final ScanProcessor scanProcessor;
private final ScheduleProcessor scheduleProcessor;
private final TagProcessor tagProcessor;
private final LatestScanProcessor latestScanProcessor;
private final RabbitMqService rabbitMqService;
#Autowired
public DashboardRoute(ScanProcessor scanProcessor,
ScheduleProcessor scheduleProcessor,
TagProcessor tagProcessor,
LatestScanProcessor latestScanProcessor,
RabbitMqService rabbitMqService){
this.scanProcessor = scanProcessor;
this.scheduleProcessor = scheduleProcessor;
this.tagProcessor = tagProcessor;
this.latestScanProcessor = latestScanProcessor;
this.rabbitMqService = rabbitMqService;
}
#Override
public void configure() throws Exception {
from(CONSUME_SCHEDULE_ROUTE)
.routeId("consume-schedule")
.process(scheduleProcessor); // no strings
}
The whole thing works when I dont autowire any of the beans and delcare the route like this.
from(CONSUME_SCHEDULE_ROUTE)
.routeId("consume-schedule")
.process("scheduleProcessor") // notice this is a string
Does camel support spring route Contructor autowiring? Do I need to take some extra config steps to handle this properly? I prefer linking beans directly that way when I refactor class names it links back ok.
I tried similar example as yours and it worked correctly. You can make sure that you have #Compoent in you route class and all the processor classes and service class.
Also you can try to add #Autowired on the local variable. (Constructor should work fine. This is just an extra stap to make sure your constructor works)
#Component
#ServletComponentScan(basePackages = "com.example.camel")
public class ServiceRoutes extends RouteBuilder {
#Autowired
private ScanProcessor scanProcessor;
#Autowired
private ScheduleProcessor scheduleProcessor;
#Autowired
private TagProcessor tagProcessor;
#Autowired
private LatestScanProcessor latestScanProcessor;
#Autowired
private RabbitMqService rabbitMqService;
#Override
public void configure() throws Exception {
from(CONSUME_SCHEDULE_ROUTE)
.routeId("consume-schedule")
.process(scheduleProcessor);
}
}
Hope this helps.
I am unable to Inject Configuration in normal utility classes ,it works fine in controller class.
#Inject
Configuration configuration
public class EmailService {
public static boolean sendEmail(final AppUser appUser,final String mailString,String subject) {
final Properties props = new Properties();
final String auth = Play.application().configuration().getString("mail.smtp.auth")
final String starttls = Play.application().configuration().getString("mail.smtp.starttls.enable");
}
}
Actually I want to remove Depricated Play.application() and want to use Configuration for that I want to Inject Configuration in this class.
Dependency injection frameworks inject dependencies when constructing instances of objects, so if you want a method to use an injected component it has to be non-static.
You want to do something like this, making your sendEmail method non-static, and providing an interface:
#ImplementedBy(EmailServiceImpl.class)
public interface EmailService {
void sendEmail(AppUser appUser, String mailString, String subject);
}
#Singleton
public class EmailServiceImpl implements EmailService {
private final Configuration config;
#Inject
public EmailServiceImpl(Configuration config) {
this.config = config;
}
public void sendEmail(AppUser appUser, String mailString, String subject) {
final Properties props = new Properties();
final String auth = config.getString("mail.smtp.auth")
final String starttls = config.getString("mail.smtp.starttls.enable");
}
}
Then inject an EmailService instance into your controller constructors.
Note: this uses #ImplementedBy for simplicity but you could also configure the binding in your Guice module, allowing you to mock it in tests.
UPDATE QUESTION:
I used JBOSS Develper Studio 8, JBOS server 7.1 based on jre 1.7 I have one J2EE project with ejb and web projects. In ejb project I have two identical ejb 3.1 In web project I have only one servlet. This servlet call simple test method in first ejb and then in second ejb. First thing in test method is dependency injection for resource session context via this code
#Resource
private SessionContext context;
First ejb works ok, but second (and any following) return null for session context. This is the comlete code:
FirstServlet.java
#WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
FirstEJB firstEJB = new FirstEJB();
SecondEJB secondEJB = new SecondEJB();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println(firstEJB.helloFirst());
out.println(secondEJB.helloSecond());
}
}
FirstEJB.java
#Stateless
public class FirstEJB {
#Resource
private SessionContext contextFirst;
public String helloFirst(){
System.err.println(contextFirst.toString());
return "Hello from FirstEJB";
}
}
SecondEJB.java
#Stateless
public class SecondEJB {
#Resource
private SessionContext contextSecond;
public String helloSecond(){
System.err.println(contextSecond.toString());
return "Hello from SecondEJB";
}
}
Can anybody knows where is the problem.
The first rule for using injection is that your server (otherwise known as the "container") creates the objects that you inject.
In your case the lifecycle of each EJB instance is under the complete control of the container.
In your code, the firstEJB instance that is created by you is replaced by another instance that is created by the container. The secondEJB instance remains the one created by you (it's missing the #EJB annotation), so it has not been subjected to proper lifecycle management and has not been fully constructed with it's #Resource injection processed.
Therefore, a simple change to your servlet code:
#WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private FirstEJB firstEJB;
#EJB
private SecondEJB secondEJB;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println(firstEJB.helloFirst());
out.println(secondEJB.helloSecond());
}
}
should give you the desired result.
I try to make a little test with versioning a soap service.
My idea was that the business logic always implement the newest version and a soap service provide its functionality. To support the older version of the interface I want to map the jaxb classes via mapping framework to the newer version and then call the endpoint implementation from the older endpoint. So in endpoint v1 I inject the endpoint v2 and call it from there. But it seems, that neither cdi nor ejb injection works:
#Stateless
#WebServiceProvider(serviceName = "WebserviceV1", wsdlLocation = "META-INF/wsdl/My.wsdl", targetNamespace = "http://smitch.ch/service/v1", portName = "ServicePortV1")
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ServiceImplV1 implements ServicePortV1 {
private ModelMapper modelMapper = new ModelMapper();
#Inject
private ServiceImplV2 v2;
#PostConstruct
void configureMapping() {
PropertyMap<v1.RequestType, v2.RequesType> specialCase = new PropertyMap<>() {
protected void configure() {
//...
}
};
modelMapper.addMappings(specialCase);
}
#Override
public v1.ResponseType service(v1.RequestType soapRequest) {
v2.RequestType v2Request = map(soapRequest, v2.RequestType.class);
return map(v2.service(v2Request), v1.ResponseResponse.class);
}
}
The version 2 endpoint is defined more or less the same way, but has implemented the business logic in the body.
I always get the error
WELD-001408 Unsatisfied dependencies for type [ServiceImplV2] with qualifiers [#Default] at injection point [[field] #Inject private v1.ServiceImplV1.v2]"}}
I use JBoss EAP 6.3.
Is there some special behaviour in handling webservice endpoints?
Here some more information. Both classes are in the same package and yes, I have a beans.xml.
V2 looks like:
#Stateless
#WebServiceProvider(serviceName = "WebserviceV2", wsdlLocation = "META-INF/wsdl/MyV2.wsdl", targetNamespace = "http://smitch.ch/service/v2", portName = "ServicePortV2")
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ServiceImplV2 implements ServicePortV2 {
#Inject
private Processor processor;
#Override
public v2.ResponseType service(v2.RequestType soapRequest) {
return processor.process(soapRequest);
}
As Jan mentioned, try adding #LocalBean to the ServiceImpleV2 to add a no-interface view. Then you should be able to injet your webservice with #EJB or #Inject.
#Stateless
#LocalBean
#WebServiceProvider(serviceName = "WebserviceV2", wsdlLocation = "META-INF/wsdl/MyV2.wsdl", targetNamespace = "http://smitch.ch/service/v2", portName = "ServicePortV2")
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ServiceImplV2 implements ServicePortV2 {
#Inject
private Processor processor;
#Override
public v2.ResponseType service(v2.RequestType soapRequest) {
return processor.process(soapRequest);
}
We have a situation where we use JSR-330 based injections to configure our stand-alone Java 6 applications, which works very well for getting configuration parameters across all the layers.
We have also used JAX-WS web services for quite a while by using first stand-alone Metro distribution with Java 5 inside a web container, but with Java 6 we just use the Endpoint class to get a smaller footprint.
So now I have a situation where I have
A stand-alone Java 6 application - no servlet container (Jetty, Tomcat)
A Guice 3 Injector set up as I like it.
An Endpoint handling my #javax.jws.WebService annotated class which expose my methods as web services.
I would like the web service methods to either have their #Inject fields handled transparently, or to get access to the injector. I can grab it as a static field from the main method, but I'd like a cleaner solution.
Any suggestions?
(I understand from JAX-WS and Guice 3 that the http://jax-ws-commons.java.net/guice/ module does not work with Guice 3, and the workaround suggested is Tomcat specific)
Would JSR-250 #Resource annotations be useful here?
I'm not sure that I've understood every bit of the question. It looks to too easy for +500 bounty. Please post some code if that's not what you're searching for.
Anyway, a simple solution which creates a web service with dependency injection:
final Module module = new HelloModule();
final Injector injector = Guice.createInjector(module);
final HelloService helloService = injector.getInstance(HelloService.class);
Endpoint.publish("http://localhost:8080/helloService", helloService);
Below a more sophisticated solution with classpath scanning (Reflections) based on Marcus Eriksson's code from JAX-WS Guice integration. It publishes all classes which is annotated with #GuiceManaged as a webservice with Endpoint.publish().
private void initGuicedWebservices(final String packageNamePrefix)
throws Exception {
final Reflections reflections = new Reflections(packageNamePrefix);
final Set<Class<?>> guiceManaged =
reflections.getTypesAnnotatedWith(GuiceManaged.class);
for (final Class<?> clazz : guiceManaged) {
doGuice(clazz);
}
}
private void doGuice(final Class<?> clazz) throws Exception {
final GuiceManaged guiceManagedAnnotation =
clazz.getAnnotation(GuiceManaged.class);
final Injector injector = createInjector(guiceManagedAnnotation);
final Object serviceObject = clazz.newInstance();
injector.injectMembers(serviceObject);
final String address = guiceManagedAnnotation.address();
Endpoint.publish(address, serviceObject);
}
private Injector createInjector(final GuiceManaged guiceManagedAnnotation)
throws Exception {
final Class<? extends Module>[] moduleClasses =
guiceManagedAnnotation.module();
final List<Module> moduleInstances = new ArrayList<Module>();
for (final Class<? extends Module> moduleClass : moduleClasses) {
moduleInstances.add(moduleClass.newInstance());
}
return Guice.createInjector(moduleInstances);
}
The GuiceManaged annotation:
#Retention(RUNTIME)
#Target(TYPE)
#Documented
public #interface GuiceManaged {
public Class<? extends Module>[] module();
public String address();
}
And the HelloServiceImpl snippet:
#GuiceManaged(module = HelloModule.class,
address = "http://localhost:8080/helloService")
#WebService
public class HelloServiceImpl implements HelloService {
#Inject // bound in HelloModule
public GreetingsService greetingsService;
#Override
#WebMethod
public String sayHello(final String name) {
return greetingsService.sayHello(name);
}
}
you need to use the AbstractMultiInstanceResolver extension point.
create the annotation GuiceManaged;
#Retention(RUNTIME)
#Target(TYPE)
#Documented
#WebServiceFeatureAnnotation(id=GuiceManagedFeature.ID, bean=GuiceManagedFeature.class)
#InstanceResolverAnnotation(GuiceManagedInstanceResolver.class)
public #interface GuiceManaged {
}
implement the GuiceManagedFeature which is WebServiceFeature :
public class GuiceManagedFeature extends WebServiceFeature {
public static final String ID="FEATURE_GuiceManaged";
#FeatureConstructor
public GuiceManagedFeature()
{
this.enabled=true;
}
public String getID() {
return ID;
}
}
Implement InstanceResolver by Extending AbstractMultiInstanceResolver
public class GuiceManagedInstanceResolver extends AbstractMultiInstanceResolver {
private T instance=null;
public GuiceManagedInstanceResolver(#NotNull Class clazz)
{
super(clazz);
}
public T resolve(#NotNull Packet request) {
if(instance==null)
{
instance=create();
Injector injector= Guice.createInjector(new WebServiceModule());
injector.injectMembers(instance);
}
return instance;
}
}
Now Annotate your Service with #GuiceManaged & use #Inject for method level DI on your business method.