Jersey : use #Inject in ResourceConfig - java

I've a Configuration.java singleton class (with many properties loaded by a file) that I would like to inject in some classes in my Application.
So, I bind my injection in the ResourceConfig class with an AbstractBinder.
Now, I need to use this Configuration class in this ResourceConfig.
For example, in my Configuration class there is a property named "packages", that I have to use in ResourceConfig class in order to register package.
The issue is that the injection is not starting in the ResourceConfig class.
class Configuration {
//many properties
String packages = "";
}
class MyResourceConfig extends ResourceConfig {
#Inject
Configuration configuration;
MyResourceConfig() {
...
register(MyBinder.class); //with many injection
...
packages(configuration.packages);
}
}
So could you please advice me how to have this lifecycle ? (maybe I have to use another jersey class ?)

I realize it is a sort of a workaround, but you can achieve it by using static access to the CDI singleton object.
Something like:
#ApplicationPath("/rest")
public class RestApplication extends ResourceConfig {
public RestApplication() {
super();
super.packages(true, "com.package.name");
register(JacksonFeature.class);
register(JacksonObjectMapperProvider.class);
ModelConverters.getInstance().addConverter(
new CustomObjectMapperModelResolver(getObjectMapperProvider()));
// get the instance here ^
OpenApiResource openApiResource = new OpenApiResource();
register(openApiResource);
AcceptHeaderOpenApiResource ahoar = new AcceptHeaderOpenApiResource();
register(ahoar);
}
private static JacksonObjectMapperProvider getObjectMapperProvider() {
return CDI.current().select(JacksonObjectMapperProvider.class).get();
}
}

Related

How to call parameterised constructor present in a class which annotated with #Component inside the another class annotated #Service

I have a requirement where I want to call a parameterised constructor of a class annotated with #Component inside another class which is annotated with #Service
feel free if you didn't get my question.
#Service
Class ServiceClass{
//here I want to create ComponentClass instance by Spring.
Result result=new ComponentClass(sending data to get result);
}
#Component
Class ComponentClass {
Component(received data){
}
}
I think you should try "Autowired" keyword. It says "Hey Spring Framework try to initialize the variable for me".
#Autowired
Result result=new ComponentClass(sending data to get result);
Whenever you define a #Servive or a #Component a bean of that type will be created (keep in mind that all beans are singletons).
A bean can be injected into any other spring managed bean by making use of this annotation:
#Service
Class ServiceClass{
#Autowired
Result result;
}
Using beans (components, services etc.) is not always needed and especially in the case, you need an non-singleton class, things can get tricky because of two reasons:
You won't be able to use annotations on that class
A non-annotated (spring managed bean) class do not support injection.
To inject a bean inside a class that is not annotated you will need to define a spring context:
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}
}
and then into any class:
Class ServiceClass{
Result result = SpringContext.getBean(Result.class);
}
where result is a either component or service.

#Autowire Spring Bean with Injected Constructor args?

I have a project structure similar to the one linked here: https://stackoverflow.com/a/29583882/1243462 . I have a util library containing a Service class in one JAR, meant to be consumed from another Java library/Maven project. However, my Service class itself uses Constructor Injection. So, where the original question had:
#Service
public class PermissionsService { ... }
I have
#Service
public class PermissionsService {
public PermissionsService(#Autowired PermissionsDao dao) {
//assign private dao field to autowired dao
}
}
And, like the original post, I want to create an instance of PermissionsService and inject it into my client/consumer application. I'm not sure of how to create a Configuration class.
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
//What goes here?
}
}
For now, I have a workaround where I replaced the #Autowired PermissionsDao constructor argument with a field injection, and having a no-args constructor. This allows me to:
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
return new PermissionsService();
}
}
But, since Field injection is discouraged, what is the right way to structure this code?
In your main module
#Configuration
#Import(PersistenceConfig.class)
public class ServiceConfig() {
}
In your utils module
#Configuration
#ComponentScan(basePackages = {"path-to-persistence-service-and-any-dependencies"})
public class PersistenceConfig {
}
The fact that you use constructor injection for PermissionsDao should not matter if you get the configuration right.

Spring boot: Consider defining a bean of type 'com.repository.services.interfacename' in your configuration

I've deployed an spring boot application, where i created an interface and implement it with two classes.
public interface interfacename {
LinkedHashSet<String> names(String path);
}
And implemented classes are
#Component
public class class1 implements interfacename {
......
}
#Component
public class class2 implements interfacename {
......
}
Now i try to create an instance for both the classes using interface name,
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
It is the configuration class,
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
My Project structure is,
com.repository
application.java(#SpringApplcation)
com.repository.controller
applicationcontroller.java(#RestController)
com.repository.services
interfacename.java
interfacenameconfig.java(#configuration)
class1.java(#component)
class2.java(#component)
It throws the following error
Action:
Consider defining a bean of type 'com.repository.services.interfacename' in your configuration.
please someone guide me to solve this.
Thanks in advance
In you're usage you're saying that you want beans with the ids / names class1 and class2respectively:
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
But in the configuration you gave them different names:
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
Namely: class1Service and class2Service. Those Ids are derived from the name of the function instantiating the beans
Two possible fixes:
Give them the names you want with #Bean("class1") and #Bean("class2").
OR
Use the names they have in the qualifier, that is: #Qualifier("class1Service") and #Qualifier("class2Service")
In your configuration class you should have an annotation to prompt for component scanning to the package that your interface interfacename belongs.
E.g.:
#ComponentScan({"com.repository.services"})
In Spring-boot you usually have this annotation in the Spring boot application class
e.g.
#SpringBootApplication
#ComponentScan({"com.repository.services"})
public class MyApplication {
}
UPDATE
If you have multiple classes implementing an interface you can use the value attribute when annotating them as #Component
#Component(value="class1")
public class class1 implements interfacename
#Component(value="class2")
public class class2 implements interfacename
and then #Autowire them with #Qualifier as you already do.
Based on your last update, since the #SpringBootApplication is in the parent directory of your spring-managed beans I think you can omit the #ComponentScan annotation. Spring will scan by default all the sub-packages below com.repository.
However I still believe that the interfacenameconfig class is redundant. Why are you declaring the same beans as the ones you have annotated as #Component? Either #Component or #Bean, there is no reason having both for the same beans as far as I know and it could probably be the source of your problem.
You need to add #Service annotation above interface implementation.
e.g. #Component
public interface interfacename {
LinkedHashSet<String> names(String path);
}
#Service
public class interfaceDefinition implements interfacename{
LinkedHashSet<String> names(String path){
// write code here
}
}
I have add the qualifier annotation along with #Component annotation. Then i ensure the application it is working fine.
#Component
#Qualifier("class1")
public class class1 implements interfacename {
......
}
Thanks for the reply

How to pass parameters to REST resource using Jersey 2.5

I have a Java server which serves my clients (Not application server).
Now I'm interested to add REST support. I've initialized a Jetty server and created few REST resources.
My question is: How can I pass parameters at the creation of the REST resources?
Normally I would prefer in the constructor of each resource, but I don't control it.
I understand there is a way to inject dependencies. How to do it using Jersey 2.5??
Thank you!
Define your Application
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new FacadeBinder());
register(JacksonFeature.class);
register(MyEndpoint.class);
}
Configure injection
public class FacadeBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyManager.class).to(MyManager.class);
}
}
Inject configured classes in your endpoint
#Path("/jersey")
public class MyEndpoint {
#Inject
MyManager myManager;
...
}
I'm not sure to understand what do you mean with dependencies.
You should check this: https://jersey.java.net/documentation/latest/user-guide.html#d0e1810
Another option besides using dependency injection is to instantiate and register the REST endpoint yourself. Jersey allows you to do this in a very similar fashion as dependency injection as shown in Dymtro's example. Borrowing liberally from Dymtro, define your endpoint:
#Path("/jersey")
public class MyEndpoint {
private MyManager myManager;
public MyEndpoint(MyManager myManager) {
this.myManager = myManager;
}
....
}
Define your application:
public class MyApplication extends ResourceConfig {
public MyApplication(MyManager myManager) {
register(JacksonFeature.class);
register(new MyEndpoint(myManager));
....
}
}

Specify Custom Application Context

We are migrating some of our data services from Jersey 1.x using jersey-spring to Jersey 2.x using jersey-spring3.
We have a few test classes that inherit from JerseyTest. Some of these classes use custom applicationContext.xml files that are not specified in the web.xml file.
In Jersey 1.x the test classes that extended JerseyTest could call the super constructor with a WebappDescriptor.Builder to which a context parameter could be passed to set or override the application context path.
E.g.
public MyTestClassThatExtendsJerseyTest()
{
super(new WebAppDescriptor.Builder("com.helloworld")
.contextParam( "contextConfigLocation", "classpath:helloContext.xml")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build());
}
How can the same be achieved with Jersey 2.x?
I have combed through the API docs, user guides and some of the sources but was unable to find an answer.
This didn't work for me as I was not using the .xml style configuration, I was using #Configuration annotations. So I had to directly provide the application context to the ResourceConfig class.
I defined the configure method in my JerseyTest like so:
#Override
protected Application configure() {
ResourceConfig rc = new ResourceConfig();
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
rc.property("contextConfig", ctx);
}
where SpringConfig.class is my class with the #Configuration annotation and
importing org.springframework.context.annotation.AnnotationConfigApplicationContext
Lets assume your Application looks like:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
/**
* Register JAX-RS application components.
*/
public MyApplication () {
// Register RequestContextFilter from Spring integration module.
register(RequestContextFilter.class);
// Register JAX-RS root resource.
register(JerseySpringResource.class);
}
}
Your JAX-RS root resource like:
#Path("spring-hello")
public class JerseySpringResource {
#Autowired
private GreetingService greetingService;
#Inject
private DateTimeService timeService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getHello() {
return String.format("%s: %s", timeService.getDateTime(), greetingService.greet("World"));
}
}
And you have spring descriptor named helloContext.xml available directly from your class-path. Now you want to test your getHello resource method using Jersey Test Framework. You can write your test like:
public class JerseySpringResourceTest extends JerseyTest {
#Override
protected Application configure() {
// Enable logging.
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
// Create an instance of MyApplication ...
return new MyApplication()
// ... and pass "contextConfigLocation" property to Spring integration.
.property("contextConfigLocation", "classpath:helloContext.xml");
}
#Test
public void testJerseyResource() {
// Make a better test method than simply outputting the result.
System.out.println(target("spring-hello").request().get(String.class));
}
}

Categories

Resources