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);
}
Related
Jersey normally uses HK2 dependency injection, but I would like to use Jersey with Dagger 2. Both Dagger and HK2 implement JSR 330, which I have taken as evidence that this should be possible without too much effort. I found ways to make Jersey work with CDI (e.g. Weld), Spring DI and Guice, but I can't find anything on Dagger.
To provide some context: I'm running a Grizzly–Jersey server in an SE environment, not in an EE container. My Maven project has com.google.dagger:dagger and org.glassfish.jersey.containers:jersey-container-grizzly2-http as dependencies, but not org.glassfish.jersey.inject:jersey-hk2, since I want to replace HK2 with Dagger.
The resource classes look like this:
#Path("/example")
public final class ExampleResource {
private final Dependency dependency;
#Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
And the Dagger component could e.g. be defined as follows:
#Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
So that the main method would look similar to:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = UriBuilder.fromUri("http://0.0.0.0/").port(80).build();
final ResourceConfig resourceConfig = new ResourceConfig();
// how to initialize `resourceConfig` using `application`?
final HttpServer httpServer = GrizzlyHttpServerFactory
.createHttpServer(baseUri, resourceConfig, false);
try {
httpServer.start();
} catch (final IOException ex) {
...
}
}
}
Running the application immediately results in an exception: IllegalStateException: InjectionManagerFactory not found. It seems that a Dagger implementation of this factory is needed.
My question is: how to integrate Dagger with Jersey?
You shouldn't think of it as "how to integrate dagger with jersey". Figure out how to setup jersey, then once you have that figured out, then you can worry about using dagger.
Here's (very roughly) how I would do it.
Create your own implementation of the ResourceConfig class.
#ApplicationPath("/service")
public class MyResourceConfig extends ResourceConfig {
#Inject
public MyResourceConfig(
#Nonnull final ExampleResource exampleResource) {
this.register(exampleResource);
}
}
Then create a module that sets up everything you need to create an HttpServer
#Module
public class MyServiceModule {
#Provides
#Singleton
#Named("applicationPort")
public Integer applicationPort() {
return 80;
}
#Provides
#Singleton
#Named("applicationBaseUri")
public URI baseUri(
#Named("applicationPort") #Nonnull final Integer applicationPort) {
return UriBuilder.fromUri("http://0.0.0.0/").port(applicationPort).build();
};
#Provides
#Singleton
public HttpServer httpServer(
#Named("applicationBaseUri") #Nonnull final URI applicationBaseUri,
#Nonnull final MyResourceConfig myResourceConfig) {
return GrizzlyHttpServerFactory
.createHttpServer(applicationBaseUri, myResourceConfig, false);
}
}
Then create your component that exposes the HttpServer. I typically like to make components that expose as little as possible. In this case, all you need to expose is the HttpServer.
#Singleton
#Component(modules = { MyServiceModule.class })
protected interface ServiceComponent {
HttpServer httpServer();
#Component.Builder
interface Builder {
// Bind any parameters here...
ServiceComponent build();
}
}
Then just go ahead and build your component, and start your HttpServer
public static void main(String[] args) {
final ServiceComponent component = DaggerServiceComponent.builder().build()
try {
component.httpServer().start();
} catch (Exception ex) {
// handle exception...
}
}
One more thing to note. I personally do not ever use the #Named("") annotation. I prefer to use a Qualifier. So you create a Qualifier annotation with a unique value. Then you can inject things like
#Provides
#Singleton
#MyUniqueQualifier
public String myUniqueQualifierProviderValue() {
return "something";
}
Then when injecting it
#Inject
public SomeClass(#MyUniqueQualifier #Nonnull final String myUniqueQualifiedValue)
If you use the #Named annotation you don't get compile time checks for conflicts or missing values. You would find out at run time that a value was not injected or then name conflicts with something else. It gets messy quick.
You need to implement an InjectionManagerFactory that will return an InjectionManager delegating to Dagger and have it registered as a service by putting an entry in META-INF/services, similar to the hk2 one here:
https://github.com/jersey/jersey/blob/master/inject/hk2/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
but referencing your own implementation.
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
I am using wildfly 10.1.0 and JavaEE 7
I've got this interface:
public interface TestEjb {
String something();
}
and this Ejb class implementing it:
#LocalBean
#Stateless
public class TestEjbImpl implements TestEjb {
#Override
public String something() {
return "Hello world";
}
}
When I am injecting it to my #Path annotated jax-rs class using
#Inject
private TestEjb testEjb;
It gives an error saying "WELD-001408: Unsatisfied dependencies for type TestEjb with qualifiers #Default"
But when I inject it like
#Inject
private TestEjbImpl testEjb;
it works fine.
And which is surprising both ways work with no problems in jboss-eap-6.4. But why?
First of all, you are mixing CDI injection with EJB injection. Rather use #EJB (instead of #Inject) when injecting your EJB.
#LocalBean has a no-interface view. So, you have an interface with no view annotation and a bean with a no-interface view annotation. The EJB Container understands it as a no interface view.
The best way will be to annotate the TestEjb interface with #Local view and remove the #LocalBean from the TestEjbImpl implementation in order for your solution to work.
Interface
#Local
public interface TestEjb {
String something();
}
EJB
#Stateless
public class TestEjbImpl implements TestEjb {
#Override
public String something() {
return "Hello world";
}
}
Injection time
#EJB
private TestEjb testEjb;
I hope this helps.
Further reading...
I want to call my Spring bean from my EJB Session Bean. Here is an example scenario that I want to achieve.
Spring Interface:
public interface ReqSpring {
public String processMsg(String msg);
}
Spring Bean:
#Component
public class ReqStringImpl implements ReqSpring{
public String processMsg(String msg) {
return "Msg ["+msg+"] is processed";
}
}
EJB Interface:
#Remote
public interface EjbService{
String echo(String msg);
}
EJB Session Bean:
(please notice that I have used #Autowired over a Spring object)
#Stateless(name = "EjbWS", mappedName = "EjbWS")
#WebService(name = "EjbService", portName = "EjbServicePort")
public class EjbServiceBean implements EjbService {
=====> #Autowired
=====> private ReqSpring reqSpring;
public EjbServiceBean() {
}
#WebMethod
public String echo(#WebParam(name="msg")String msg) {
// This is printing null
System.out.println("ReqSpring = "+reqSpring);
return reqSpring.processMsg(msg);
}
}
My Application failed to load the ReqSpring object from my EJB and always generating NullPointerException. Any idea why this is happening?
You can't inject a Spring Bean into a EJB like that because the EJB is not managed by the Spring container. Anyway, by using the SpringBeanAutowiringInterceptor, you will be able to do it. Try with this annotation :
#Stateless(name = "EjbWS", mappedName = "EjbWS")
#WebService(name = "EjbService", portName = "EjbServicePort")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class EjbServiceBean implements EjbService {
#Autowired
private ReqSpring reqSpring;
public EjbServiceBean() {
}
#WebMethod
public String echo(#WebParam(name="msg")String msg) {
System.out.println("ReqSpring = "+reqSpring);
return reqSpring.processMsg(msg);
}
}
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.