This is my jersey config class
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig{
public JerseyApplication() {
packages("com.ems");
register(EmployeeService.class);
}
}
Here autowiring of employeeService is giving a null pointer exception
#Path("/ems")
#Component
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#GET
#Path("/employees")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<Employee> getEmployees() {
return employeeService.getEmployees();
}
}
I have tried everything
In my employeeServiceImpl I have #service annotation
Still, it is not working.
To configure the dependency injection using the built in DI framework (HK2), you should use an AbstractBinder, as mentioned in some answers in Dependency injection with Jersey 2.0.
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.ems");
register(new AbstractBinder() {
#Override
protected void configure() {
bind(EmployeeService.class)
.to(EmployeeService.class)
.in(Singleton.class);
}
});
}
}
Secondly, you do not use the #Autowired annotation. This annotation is specifically for Spring. For standard injection with Jersey, just use the #Inject annotation. Also remove the #Component annotation, as this is also for Spring.
As an aside, if you do want to integrate Spring with Jersey, you should read Why and How to Use Spring With Jersey. It will break down what you need to understand about integrating the two frameworks.
You should register Controller not Service class.
Sample
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig{
public JerseyApplication() {
packages("com.ems");
register(EmployeeRestController.class);
}
}
Related
How come application.properties will work in a RestController, but not in a service class?
//application.properties
test=test
Works Perfect!
#RestController
public class invitecontroller {
#Autowired inviteconfig inviteconfig;
#PostMapping("/v1/invite")
public void invite(#RequestBody XXX XXX) {
System.out.println(inviteconfig);
}
}
Returns "Null"
#Service
public class inviteservice {
#Autowired inviteconfig inviteconfig;
public void invite() {
System.out.println(inviteconfig);
}
}
#Configuration
#Data
public class inviteconfig {
private String test;
}
The inviteservice class is not configured for Spring IoC (Inversion of Control) as a bean, so Spring will not handle the inviteservice class lifecycle. In this case, #Autowired is useless.
To fix this try to add #Component annotation to invitesevice, to declare it as a component:
#Component
public class inviteservice {
#Autowired inviteconfig inviteconfig;
public void invite() {
System.out.println(inviteconfig);
}
}
In the case of the controller, with #RestController, Spring will recognize your class as a Spring component.
Finally, don't forget to inject inviteservice using Spring IoC (using #Autowired annotation, or other means)
inviteservice class should be annotated with #Component or #Service
#Component
public class inviteservice {
...
I am trying to set up a Spring MVC app but every time I call the http://localhost:9001/tasks API from postman I get the following error:
Here is my code:
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TaskManagerApplication {
public static void main(String[] args) {
SpringApplication.run(TaskManagerApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:4200");
}
};
}
}
TaskRepository:
#Path("tasks")
#ApiIgnore
#Component
#AllArgsConstructor
public class TaskResource {
private final TaskService taskService;
#GET
#Produces(APPLICATION_JSON)
public List<Task> getAllTasks() {
return taskService.getTasks();
}
TaskService:
#Service
#RequiredArgsConstructor
public class TaskService {
private final TaskRepository taskRepository;
public List<Task> getTasks() {
return taskRepository.findAll();
}
Project Structure:
You are using JAX-RS in spring boot. Spring handles rest in its own way, if you want to use JAX-RS instead of Springs Rest Annotations, you need to do some extra configurations.
First, you need to add a JAX-RS dependency in your build.gradle or pom.xml file. I guess you have already done that. Jersey is one of the JAX-RS implementation, if you want to add this, you need to do the following.
build.gradle
implementation "org.springframework.boot:spring-boot-starter-jersey"
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
After that, you need to register the JAX-RS endpoints with Spring. I guess you missed this step.
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
#Configuration
public class JaxrsConfig extends ResourceConfig {
public JaxrsConfig() {
register(TaskResource.class);
}
}
After this, your JAX-RS endpoints will be registered with spring.
But I will suggest you to follow spring annotations if you are using spring. If you use spring annotations your code will look like this.
#RestController
#RequestMapping(path = "tasks")
public class TaskResource {
#GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE)
public List<String> getAllTasks() {
return Arrays.asList("a","b");
}
}
Also you will need to remove JAX-RS from spring to use this Spring MVC annoatations to work.
I use java 8 SE and jersey. I found example of jwt service here,
there is used java 6 EE.
Does someone know about analogs of this annotations or other solution of this problem?
I solved it by replacing this annotations on #Singelton and adding
ApplicationBinder
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(UserService.class).to(UserService.class).in(Singleton.class);
}
}
ResourceConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(new ApplicationBinder());
packages(true, "api");
}
}
than I just can inject bean-classes by annotation #Inject
I am able to access HttpServletRequest by using #Context annotation in my rest service. But unable to access the same in repository class.I do not want to pass the request form MyService to MyRespository while calling methods.
#Path("/someUrl")
public MyService{
#Context
private HttpServletRequest request;
#Get
public void someMethod()
{
myRepository.someMethod();
}
}
But same annotation not working for my Repository class
#Repository
public MyRepository
{
#Context
private HttpServletRequest request;
public void someMethod()
{
//need request here
}
}
it injection null request. Not sure why this is not working.
The problem is the way Jersey (and its DI framework HK2) is integrated, is that Spring components can be injected into Jersey (HK2) components, but not vice versa. HttpServletRequest is bound as a Jersey component.
What you can do is create an HK2 service, that wraps the Spring repo, and the HttpServletRequest. IMO, it is better design anyway. A repository shouldn't be concerned with the HttpServletRequest, it is only concerned with data.
So you can have
public class MyService {
#Inject // or #Autowired (both work)
private MyRepository repository;
#Context
private HttpServletRequest request;
}
Then bind the service with HK2
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class AppBinder extends AbstractBinder {
#Override
public void configure() {
bindAsContract(MyService.class).in(RequestScoped.class);
// note, if `MyService` is an interface, and you have
// an implementation, you should use the syntax
//
// bind(MyServiceImpl.class).to(MyService.class).in(...);
//
// Then you inject `MyService`. Whatever the `to(..)` is,
// that is what you can inject
}
}
And register the binder with Jersey
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(new AppBinder());
}
}
Then you can inject MyService into your resource class.
If you don't want to go this route, then you need to make MyRepository an HK2 service, or use a an HK2 Factory to wrap the repository, and explicitly inject it. Something like
import javax.inject.Inject;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.springframework.context.ApplicationContext;
public class MyRepositoryFactory implements Factory<MyRepository> {
private final MyRepository repo;
#Inject
public MyRepositoryFactory(ApplicationContext ctx, ServiceLocator locator) {
MyRepository r = ctx.getBean(MyRepository.class);
locator.inject(r);
this.repo = r;
}
#Override
public MyRepository provide() {
return repo;
}
#Override
public void dispose(MyRepository t) {/* noop */}
}
Then register the factory
#Override
public void configure() {
bindFactory(MyRepositoryFactory.class).to(MyRepository.class).in(Singleton.class);
}
If you do the above, then you just use the MyRepository, instead of adding the service layer. Basically you need to get the repo from Spring, and explicitly inject it with the HK2 ServiceLocator (which is the HK2 analogue of the Spring ApplicationContext).
I'm trying to create a simple REST service with JAX-RS (Jersey), without using Spring. And I'm using Joda as date fields in my entity.
To configure automatic json mapping, I create a JsonMapperProvider, where I add JodaModule:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JsonMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper objectMapper;
public JsonMapperProvider() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new JodaModule());
}
#Override
public ObjectMapper getContext(Class<?> arg0) {
return objectMapper;
}
}
This is my Resource class:
#Path("users")
public class UserController {
#Inject
private UserService userService;
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public User getUserById(#PathParam("id") Long id) {
return userService.findById(id);
}
}
And I'm using a "no web.xml" configuration, with this class:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
}
But it doesn't work... the LocalDate field in User entity is always returned empty.
The only workaround I found is to register all the components (including JacksonFeature class from jersey-media-json-jackson) in the ResourceConfig class, like this:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
public RestApplication() {
super(
UserController.class,
JsonMapperProvider.class,
JacksonFeature.class
);
}
}
Is there another solution to this problem? I'd rather not to register all my services and other stuff in this class manually...
No, this is how it's supposed to work. You can also override the methods in javax.ws.rs.core.Application instead of extending ResourceConfig