Can you combine Jersey and Spring (#Provider and #Component)? - java

What I have already working:
Spring version 4.1.4.RELEASE.
Jersey version 2.14.
I added maven dependency jersey-spring3 and excluded spring from it (spring-core, spring-web, spring-beans).
Spring components are scanned for - #ComponentScan.
"Controllers" are registered in Jersey's ResourceConfig...
... and are annotated with #Path and #Component...
... so that #Autowired beans fetch (#Transactional) POJOs from database...
... and Jersey with help of certain #Providers returns them in form of JSON.
What seems to be the problem is that a classes annotated with #Provider stop working as soon as I add annotation #Component.
Was anyone successful in combining those annotations? If yes, then what am I missing? If not, then it'll be quite clear that I have to move to alternative libraries. :)

While I think that using RestController could be the better way to go, this code (below) works - so my answer may be useful to everyone who is forced to use Jersey + Spring (for whatever reason...)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import javax.persistence.EntityNotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class EntityNotFoundExceptionMapper implements ExceptionMapper<EntityNotFoundException> {
private final ApplicationContext applicationContext;
#Autowired
public EntityNotFoundExceptionMapper(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public Response toResponse(EntityNotFoundException exception) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}

You could use Spring's RestController, which was added in Spring 4.0. It allows you to use Autowired among other things.
#RestController
#RequestMapping("/msg")
public class MessageRestController {
#Autowired
private IShortMessageService shortMessageService;
#RequestMapping(value = "/message-json/{id}", method = RequestMethod.GET, produces = "application/json")
public ShortMessageDto getMessageJSONById(#PathVariable String id) {
Long id_value = null;
try {
id_value = Long.parseLong(id);
ShortMessageDto message = shortMessageService.getById(id_value);
if(message != null){
return message;
} catch (NumberFormatException e){
// log message
}
return null;
}
}

Related

spring boot constructor parameter could not be found

I am working on spring boot app with tutorial. I did everything like guy from tutorial but still have problem with some constructor:(
The error is:
Parameter 0 of constructor in com.wewtorek.shop.controllers.AdminController required a bean of type 'com.wewtorek.shop.models.data.PageRepository' that could not be found.
Code is:
package com.wewtorek.shop.controllers;
import com.wewtorek.shop.models.data.Page;
import com.wewtorek.shop.models.data.PageRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
#Controller
#RequestMapping("/admin")
public class AdminController {
private PageRepository pageRepository;
public AdminController(PageRepository pageRepository) {
this.pageRepository = pageRepository;
}
#GetMapping
public String admin(Model model) {
List<Page> pages = pageRepository.findAll();
model.addAttribute("pages", pages);
return "admin";
}
}
PageRepository:
package com.wewtorek.shop.models.data;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PageRepository extends JpaRepository<Page, Integer> {
}
Application:
package com.wewtorek.shop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
}
First :
#Repository is missing
#Repository
public interface PageRepository extends JpaRepository<Page, Integer> {
}
Doc : https://www.baeldung.com/spring-data-repositories
You dont have to create an constructor in controller :
It should be something like this :
public class AdminController{
#Autowired
private PageRepository pageRepository;
--- Code ---
}
#Autowired instanciate a service, you dont have to build it
BUT you have to put #Repository or #Service to use #Autowired
I take this example from my school project :
Controller
In my LoanService i call another server but u can replace it by u'r repository
Service
And last tips i promise :D, a complete NoSQL school project i did
https://github.com/juju630/ClientServeurNoSQL
( sry not native )
Without looking at your project, this is going to be hard to give a definitive solution.
What is happening is when spring tries to create the bean AdminController it can not find a unique bean as the dependency PageRepository.
A few things to look at to try to solve this
Is the bean JpaRepository<Page, Integer> annotated correctly for spring to pick it up and create an instance?
Is the bean JpaRepository<Page, Integer> being scanned by spring?
What is your package structure? this can be very important for the default scanning of spring beans.
To investigate you could add a default constructor to allow it to ignore the dependency, then debug out all beans on startup of your app using the answers
Here
I hope this helps.

calling method with Rest Template Builder

I created this rest template with the rest template builder and set connection and read timeouts. I need to call this rest template from other methods in the program, but am unsure how to do so. please help, thanks in advance!
//create rest template with rest template builder and set connection and read timeouts #Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofMillis(connectTimeout))
.setReadTimeout(Duration.ofMillis(readTimeout))
.build();
}
// this is an example method that calls rest template, unsure what goes in the parameter section
#Bean
public example example() {
return new restTemplate(what goes here)
);
}
if you have created your customised RestTemplate, you may autowire it any class where you want to call it and use the one. if you more than 1 RestTemplates you can use #Qualifier above RestTemplate Bean and use the same in the calling class.
RestTemplateBuilder is a bean provided by Spring boot. You can inject that into any of your Spring bean classes.
Then you just want to configure your restTemplate at the creation of your Spring bean class and store it as a field. You can do something like below (This is not the one and only way).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
#Configuration
public class MyExampleRestClientConfiguration {
private final RestTemplateBuilder restTemplateBuilder;
#Autowired
public MyExampleRestClient(RestTemplateBuilder restTemplateBuilder) {
this.restTemplateBuilder = restTemplateBuilder;
}
#Bean
public RestTemplate restTemplate() {
return restTemplateBuilder
.setConnectTimeout(Duration.ofMillis(connectTimeout))
.setReadTimeout(Duration.ofMillis(readTimeout))
.build();
}
}
Now in Some other spring bean class, you can simply wire the restTemplate bean and re-use.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
public class MyExampleRestClient {
private final RestTemplate restTemplate;
#Autowired
public MyExampleRestClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
//Now You can call restTemplate in any method
}
You may refer this for more.

MappingJackson2JsonView Bean breaks after adding ViewResolverRegistry to SpringWebConfig

RESOLVED - see answer.
I've looked through many similar questions and don't see a similar case right off. Certainly this isn't a unique situation and I'm just missing it?
Update A Spring example I found shows a priority property that may help here, but I have only found the XML example. Question expanded below.
Problem Summary
Two view resolvers appear to be conflicting in my SpringWebMVC application.
Problem Details
I'm work on a web app using Spring 4.0.3-RELEASE and have recently added Jackson to support returning Json from calls to a specific controller. This was working until I added an #Override to my SpringWebConfig for configureViewResolvers. Now my calls to my controller which was serving Json just return the template name which should call the Jackson mapper bean.
The big question
How can I make these two coexist? I have found that I can call:
registry.order(int)
and set it to 9 just to make sure it was last, but it still intercepted the jsonTemplate response from the controller. I don't see a way to set an order for the MappingJackson2JsonView bean. #Bean(order=0), for example, is invalid.
Things Tried
Redacting the ViewResolverRegistry, as expected, produces an error when trying to get mapped jsp views.
javax.servlet.ServletException: Could not resolve view with name 'someView' in servlet with name 'spring-mvc-dispatcher'
As noted in the question statement above, I've tried setting the order on the registry for the ViewResolverRegistry, but this did not help.
I also have tried adding the following to the MappingJackson2JsonView instance, view:
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
But as before, this doesn't prevent the ViewResolverRegistry from intercepting "jsonTemplate" before the Jackson mapper can process it.
I also have changed the load order of the configs in the AppInitializer, the code below has been updated to reflect the new load order, but this also did not help.
Reading through the Spring documentation a bit more, it appears that adding a ContentNegotiationConfigurer is going to be what I need to resolve this and I'm presently looking at how to get this to work in a way that preserves auto mapping the Model returned to the jsonTemplate view. Exapmles I've seen so far use a jsp as a view with specific properties called out, which defeats the purpose of using a Json Mapper.
Configuration
I have multiple config classes defined in my package com.mytest.config.
AppInitializer.java handles adding the *config classes to the context.
package com.mytest.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class AppInitializer implements WebApplicationInitializer {
private Logger logger = LoggerFactory.getLogger(AppInitializer.class);
#Override
public void onStartup(ServletContext container) throws ServletException {
try {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(JSONConfiguration.class);
ctx.register(SpringWebConfig.class);
ctx.setServletContext(container);
container.addListener(new ContextLoaderListener(ctx));
container.addListener(new RequestContextListener());
logger.info("Created AnnotationConfigWebApplicationContext");
ServletRegistration.Dynamic dispatcher = container.addServlet("spring-mvc-dispatcher", new DispatcherServlet(ctx));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
logger.info("DispatcherServlet added to AnnotationConfigWebApplicationContext");
} catch (Exception e) {
logger.error(e.getLocalizedMessage(), e);
}
}
}
SpringWebConfig.java is where I register the majority of my beans.
package com.mytest.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages={"com.mytest.controller","com.mytest.bean","com.mytest.model"})
#PropertySource(value={"classpath:application.properties"})
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Autowired
private Environment env;
private Logger logger = LoggerFactory.getLogger(SpringWebConfig.class);
// bunches of beans such as JdbcTemplate, DataSource... omitted for simplicity
#Override // apparent problem location -- needed for jsp resolving
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/html/",".jsp");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
logger.info("DefaultServletHandlerConfigurer enabled");
}
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new com.honda.hrao.rid.config.RequestInterceptor());
logger.info("RequestInterceptor added to InterceptorRegistry");
}
}
JSONConfiguration.java is a controller I set up just for JSON.
package com.mytest.config;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
#Configuration
#ComponentScan(basePackages = {"com.mytest.controller"})
#EnableWebMvc
public class JSONConfiguration {
private Logger logger = LoggerFactory.getLogger(JSONConfiguration.class);
#Bean // needed for JSON conversion of bean responses
public View jsonTemplate() {
logger.info("Registered MappingJackson2JsonView");
MappingJackson2JsonView view = new MappingJackson2JsonView();
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
view.setPrettyPrint(true);
return view;
}
#Bean
public ViewResolver viewResolver() {
logger.info("Starting ViewResolver bean");
return new BeanNameViewResolver();
}
}
Implementation
In my Controller, the following method should return JSON.
#Autowired
AppConstants appConstants;
#RequestMapping(method = RequestMethod.GET, value = "getAppConstants")
public String getAppConstants(Model model) {
model.addAttribute("AppConstants",appConstants);
if(appConstants==null) {
Logger.error("appConstants not autowired!!!");
return null;
}
return "jsonTemplate";
}
As mentioned above in Things Tried, this works fine if I remove the ViewResolverRegistry bean from the SpringWebConfig and if I leave the bean in place, the above controller method returns
404, /WEB-INF/views/html/jsonTemplate.jsp
The requested resource is not available.
-- which I understand. That's what the view resolver should do. How do I make my JSON calls bypass this?
It turns out there were only a couple of things missing. The first was to add the following annotation to the bean declaration for the mapper:
#Primary
So now, the bean setup looks like this.
#Bean // needed for JSON conversion of bean responses
#Primary
public View jsonTemplate() {
logger.info("Registered MappingJackson2JsonView");
MappingJackson2JsonView view = new MappingJackson2JsonView();
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
view.setPrettyPrint(true);
return view;
}
The second was to use a ContentNegotiationConfigurer. In my SpringWebConfig, I added the following:
public void configurationContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.ignoreUnknownPathExtensions(false)
.defaultContentType(MediaType.TEXT_HTML);
}
and changed my configureViewResolvers function as follows:
#Override // needed for jsp resolving
public void configureViewResolvers(final ViewResolverRegistry registry) {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
registry.enableContentNegotiation(view);
registry.jsp("/WEB-INF/views/html/",".jsp");
}
One clue was found in this example. The rest came from the Spring documentation.

get a null object after used #autowired to DI

I have a utils class that use #Autowired to inject a repository using spring-boot-starter-data-jpa. But when I used this repository to access the database, it said the repository is null. I used the same method in my controller and it works well. And here is my Utils.class
package com.example.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import com.example.dao.RuleRepository;
import com.example.model.Project;
import com.example.model.Rule;
public class Judge {
#Autowired
RuleRepository ruleRepository;
public boolean ageJudge(Project project) {
try {
if (ruleRepository == null)
{
System.out.println("yes");
}else {
System.out.println("false");
}
return false;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
}
Here is my Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan(basePackages = {"com.example"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
This is the RuleRepository.java
package com.example.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Project;
import com.example.model.Rule;
public interface RuleRepository extends JpaRepository<Rule, Integer>{
Rule findById(Integer id);
Rule findByRuleName(String ruleName);
}
It is the directory.
The RuleRepository works well in controller. So, what is the problem?
Your util class Judge is a plain POJO not a Spring bean and you can only inject Spring beans inside another Spring beans not Plain POJOs.
If you wish to use your ruleRepository bean inside Judge then make it a Spring component using #Component annotation:
#Component
public class Judge {
#Autowired
RuleRepository ruleRepository;
..............................
}
User #Service annotation of Judge class is acting as business logic implementation class.
Your Judge should be annotated #Component
#Component
public class Judge{
// ...
}
so that Spring will instantiate a Judge bean and it will be available for injection. You can then use that judge bean in any managed bean (e.g: a controller)
// SomeController
#Autowired
Judge judge;
But if you instantiate judge object your self, like this:
Judge judge2 = new Judge();
your repository will be null, be cause Spring have nothing to do with judge2 object, it is not managed by Spring.
You need to make your Judge class at least a #Component of your project, which will make your class managed by Spring, therefore your RuleRepository will be instantiated.
If it doesn't work on first try, you will have to add your com.example.controller package in the list of packages to scan, in the #ComponentScan annotation
First as everyone mention your class Judge does not have #Component annotations.
The other thing is, maybe my Spring is getting little bit rusty.
But as far as I remember, I think your repository also require to have #Component or #Repository annotation

Injecting HttpRequest At Class Level [duplicate]

I've got a session scoped CDI bean, and I need to somehow access the HttpServletRequest object in this bean's #PostConstruct method. Is it possible? I've tried to Inject such an object, but it results in:
WELD-001408 Unsatisfied dependencies for type [HttpServletRequest] with qualifiers [#Default] at injection point [[field] #Inject ...]
As I understood while googling, the Seam framework has such a functionality, but I have a standard Java EE application on a GlassFish server.
Is it even possible to somehow pass the request to a CDI bean's #PostConstruct method?
As per your comment, you want access to the user principal. You can just inject it like this: #Inject Principal principal; or #Resource Principal principal;, see Java EE 6 Tutorial.
Update
I'll answer your direct question. In Java EE 7 (CDI 1.1) injection of HttpServletRequest is supported out of the box. In Java EE 6 (CDI 1.0) however, this is not supported out of the box. To get it working, include the class below into your web-app:
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#Produces
private ServletRequest obtain() {
return SERVLET_REQUESTS.get();
}
}
Note: Tested only on GlassFish 3.1.2.2
When using the code from rdcrng be aware of the following:
* The producer-method obtain is dependent-scoped, thus is only called once for application scoped beans (and will resolve to problems for every other request except the first)
* You can solve this with #RequestScoped
* When RequestScoped annotated, you will only get a proxy, and thus you cannot cas it to HttpServletRequest. So you maybe want a producer for HttpServletRequest.
Also note: As per CDI specification link passage 3.6, java ee beans are NOT consideres managed beans. Thus you will end up with two instances of CDIServletRequestProducingListener - one managed by the Java EE container, one managed by the CDI-container. It only works because SERVLET_REQUESTS is static.
Following the modified code for your convenience.
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<ServletRequest>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#RequestScoped
#Produces
private HttpServletRequest obtainHttp() {
ServletRequest servletRequest = SERVLET_REQUESTS.get();
if (servletRequest instanceof HttpServletRequest) {
return (HttpServletRequest) servletRequest;
} else {
throw new RuntimeException("There is no HttpServletRequest avaible for injection");
}
}
}

Categories

Resources