Missing dependencies for HttpServletRequest with Jersey - jersey

I have a Standalone Jersey server running at the beginning of my JunitTest. I'm testing if my JaxRS controller works, as well as my custom HttpClient. Please note that I've always been able to use this JaxRsResourceController embedded in glassfish.
Here is the JaxRsController (light version)
#Path("root")
public class JaxRsResourceController implements
ResourceController<HttpServletRequest> {
#Context
private UriInfo context;
#Context
HttpServletRequest request;
#Context
HttpServletResponse response;
#GET
public String hello(){
System.out.println("Uri is "+this.context.getBaseUri().toString());
return "Hello "+peoples;
}
}
I have no problem with the client, but when I start the server, I have :
GRAVE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletRequest com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.request
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletResponse com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.response
at com.sun.jersey.api.container.httpserver.HttpServerFactory.create(HttpServerFactory.java:172)
at com.robustaweb.library.rest.server.JerseyServer.startServer(JerseyServer.java:44)
Basically it says that at the #Context injection time, there is no dependency on the HttpServletRequest.
However if I remove the #Context annotations on request and response, but keep it for UriInfo context, it's ok, and I can read the Uri.
I changed a few times the Maven pom wich is now to force the libs in:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
Any idea ?

servlet dependencies were separated to another module, try adding
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.14</version>
</dependency>
to your pom.

It was not easy, but I found out. The thing is that in my JUnit test, I was creating the server like this :
HttpServer server = HttpServerFactory.create(url);
But that way, you create a lightweight container that does not have servlet containers, and so is the failure reason. So in order to have it all, I used the jersey-test-framework that allow to use the Grizzly web container (or even Embedded glassfish).
Here is the maven :
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- Unit test are using jersey server directly -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.test.framework</groupId>
<artifactId>jersey-test-framework</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
Here is the JerseyServerTest : note that it extends JerseyTest
public class JerseyServerTest extends JerseyTest {
protected String baseUri = "http://localhost:" + TestConstants.JERSEY_HTTP_PORT + "/";
public JerseyServerTest() throws Exception {
super("com.robustaweb.library.rest.controller");
/*
It's possible to NOT call the super() but to manually do :
1) ApplicationDescriptor appDescriptor = new ApplicationDescriptor()
.setRootResourcePackageName(resourcePackageName) // resource packages
.setContextPath(contextPath) //context of app
.setServletPath(servletPath); // context of spi servlet
2)setupTestEnvironment(appDescriptor);
*/
}
#Test
public void testHelloWorldRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.GET("", null);
System.out.println(result);
}
#Test
public void testDeleteRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.DELETE("john", null);
System.out.println(result);
}
}
And finally the Resource file, that contains #GET and #DELETE
#Path("root")
public class JaxRsController extends JaxRsResourceController{
List<String> peoples = new ArrayList<String>();
#GET
public String hello(){
System.out.println("Uri is "+getUri());
return "Hello "+peoples;
}
#DELETE
#Path("{name}")
public String deletePeople(#PathParam("name") String name){
System.out.println("deleting "+name);
this.peoples.remove(name);
return String.valueOf(peoples.size());
}
}
And now it works !
I had some help in this article, and there is a small chapter on the documentation. Beeing able to attach the source code of the Jersey framework really helped, so thantks to IntelliJ also.

Related

Not able to inject #Service and #Contract dependency in my resource class

On base of the guide from this blog, Roll your own Auto Discovery with Jersey and HK2, I have the follow resource POJO:
#Path("Test")
public class TestResource {
#Inject
private TestService service;
#GET
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Set<Test> getTests() {
return service.getAllTests();
}
}
The TestService:
#Contract
public interface TestService {
public Set<Test> getAllTests();
}
The TestServiceImpl
#Service
public class TestServiceImpl implements TestService {
#Override
public Set<Test> getAllTests() {
Set<Test> tests = new HashSet<>();
Test c = new Test();
c.setName("test");
tests.add(c);
return tests;
}
}
The Jersey dependency in pom.xml is of version 2.25.1
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2</artifactId>
<version>2.5.0-b36</version>
</dependency>
In order to make Jersey scan the #Service and #Contract classes automatically, I used the inhabitant-generator plugin with version 2.5.0-b36:
<plugin>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-inhabitant-generator</artifactId>
<version>2.5.0-b36</version>
<executions>
<execution>
<goals>
<goal>generate-inhabitants</goal>
</goals>
</execution>
</executions>
</plugin>
There is the corresponding Feature implementation:
public class AutoServiceDiscovery implements Feature {
#Override
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
populator.populate(new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
new DuplicatePostProcessor());
} catch (IOException | MultiException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
return true;
}
}
And it is indeeded registered through my ResourceConfig class:
#ApplicationPath("/*")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("resources");
register(new AutoServiceDiscovery());
}
}
However, I send request to the /test, got the following error:
MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for
injection at SystemInjecteeImpl(requiredType=TestService,parent=TestResource,qualifiers=
{},position=-1,optional=false,self=false,unqualified=null,1947073589)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of
rx.practice.ee.jaxrs.resources.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on
rx.practice.ee.jaxrs.resources.TestResource
org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:89)
org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:250)
org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:358)
org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:487)
org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
...
Question: Anyone knows why the #Service class cannot be injected? I am using Tomcat server
After a couple of days research on the source code of inhabitat-generator, I figured out that in case of web application package,war, the locator file is not generated in META-INF/hk2-locator as demonstracted in the HK2 Inhabitant Generator office site in case of using jar as deployment package. The source code of AbstractInhabitantsGeneratorMojo.java told that in case of war, locator files are generated in hk2-locator, and this is not mentioned in the HK2 Inhabitant Generator office site.
However, when constructing the ClasspathDescriptorFileFinder without the directory names argument in the bootstrap class, AutoServiceDiscovery, it is only compatible with jar as deployment package, meaning it is only finding files in META-INF/hk2-locator.
So the better solution would be not to use inhabitant-generator plugin but the metadata-generator dependency, which is an annotation processor at compile time and, it is proved out-of-the-box.
If someone is persistent to using this plugin, he/she could create his/her own ClasspathDescriptorFileFinder so that it is able to find locator files from hk2-locator
Last but not least, I also tried to use the inhabitants-generator plugin's options to generate the locator files in hk2-locator, but this seems to be next to impossible as well

log4j2 java classes do not load application.properties entries with spring boot

I am using log4j2(log4j-core and log4j-api) with Spring boot 2.2.0.RELEASE. I want to masking sensitive data inmy json payload in the logs. I have written a custom LogMaskingConverter which extends LogEventPatternConverter.
#Plugin(name = "LogMaskingConverter", category = "Converter")
#ConverterKeys({ "spi", "trscId" })
#Configuration
public class LogMaskingConverter extends LogEventPatternConverter {
#Value("${maskingFields}")
private String maskingFields;
protected LogMaskingConverter(String name, String style) {
super(name, style);
}
public static LogMaskingConverter newInstance(String[] options) {
return new LogMaskingConverter("spi", Thread.currentThread().getName());
}
#Override
public void format(LogEvent event, StringBuilder outputMessage) {
........
}
private String mask(String message) {
....
}
The problem is that the maskingFields does not get loaded from the application properties file.I read that log4j2 gets loaded before spring boot. Hence I have renamed my xml to log4j2-spring.xml so that spring boot is the first to intialise and load all the properties before it gets read via LogMaskingConverter.
Also below are my pom.xml dependencies related to log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
To summarise below code does not fetch any values:
#Value("${maskingFields}")
private String maskingFields;

Spring web app returns HTTP Status 406

I'm creating a basic spring based web app:
pom dependencies:
<properties>
<java-version>1.8</java-version>
<springframework-version>4.3.3.RELEASE</springframework-version>
<jackson-version>2.8.3</jackson-version>
<org.slf4j-version>1.7.6</org.slf4j-version>
<logback.version>1.1.7</logback.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- Jackson JSON Mapper -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- #Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
In order to skip the usage of web.xml I'm using WebApplicationInitializer:
public class AppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(SpringModule.class.getPackage().getName());
return context;
}
Here is my spring config class:
#Configuration
#ComponentScan(basePackages = "com.company.app")
public class SpringModule extends WebMvcConfigurerAdapter {
public SpringModule() {
super();
}
private MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(customJackson2HttpMessageConverter());
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new SourceHttpMessageConverter());
messageConverters.add(new FormHttpMessageConverter());
super.configureMessageConverters(messageConverters);
}
/*
* Configure ContentNegotiationManager
*/
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true).defaultContentType(
MediaType.APPLICATION_JSON);
}
Here is my test controller:
#Controller
#RequestMapping(value = "/user")
public class SomeController {
#RequestMapping(value = "/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Person helloElad() {
return new Person("some name");
}
}
When testing the controller (using browser) I'm getting:
If I'm returning a plain String it works fine.
I tries to debug method configureMessageConverters and configureContentNegotiation but for some reason it never gets there (on bootstrapping), I'm not sure it is related to the problem though.
Any ideas?
HTTP 406 is an indication that your request content is not negotiated, it is probably that necessary http message converters are not found in configuration. Simple way to add basic set of message converter would be annotating your controller #EnableMvc
I had the same problem and couldn't find a solution here or elsewhere.
I also tried the advice of applying #EnableMvc on my AppConfig but that caused a different problem in which Tomcat wouldn't even successfully start up.
Eventually, I had to rewrite my AppInit class as follows:
https://github.com/viralpatel/spring4-restful-example/tree/master/src/main/java/net/viralpatel/spring/config
Now, I'm getting JSON back when I return a POJO. I don't like this fix. The code seems incomplete compared to the AppInit shown in the problem here, but I'm unstuck.

Spring Boot + Apache Camel HTTP component crashes at start: missing EmbeddedServletContainerFactory bean

Just taking Spring-Boot for a spin and decided to mix in Camel because I need some arcane Headers work in the rest client I am working on. Setting up the application was fine until I added the camel-http component to my POM, then I get this on init:
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
I've havent got the first idea of where to start to look for the problem. I gather Spring Boot will look up the classpath and try to wire stuff up, so is there a way for the to block the Camel packages from being acted on or something of the sort?
Complete log of the start up in this Gist
Here's my main aplication code:
#ComponentScan
#EnableAutoConfiguration
public class Application {
private static ApplicationContext ctx;
public static void main(String[] args) throws Exception {
ctx = SpringApplication.run(Application.class, args);
//Right outta Spring 4 docs
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
//---
// FIXME: ugly hack to allow some POC woek while wait for proper Camel/Spring4 unit tests fix.
Application app = new Application();
app.executeTests();
}
/**
* Dev QOL - unit tests are broken for now, see:
* https://issues.apache.org/jira/browse/CAMEL-7074
* <p/>
* Waiting for fix (Too lay to checkout and build my own Camel)
*/
private void executeTests() throws Exception {
testAuth();
}
#Bean
DefaultCamelContext camelCtx() throws Exception {
DefaultCamelContext camel = new DefaultCamelContext();
camel.addRoutes(cryptsyRouteBuilder());
camel.start();
return camel;
}
#Bean
public CryptsyRouteBuilder cryptsyRouteBuilder() throws Exception{
CryptsyRouteBuilder bean = new CryptsyRouteBuilder();
bean.setCryptsy(cryptsy());
return bean;
}
#Bean
public Cryptsy cryptsy() throws IOException {
return new Cryptsy();
}
protected void testAuth() throws Exception {
ProducerTemplate producer = camelCtx().createProducerTemplate();
producer.requestBody("direct:start", "Why, hullo there", String.class);
}
}
And my POM dependencies:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>0.5.0.BUILD-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-actuator</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-javaconfig</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-quartz</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>${camel.version}</version>
</dependency>
<!-- Assorted -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
<properties>
<start-class>xxx.xxxx.Application</start-class>
<camel.version>2.12.2</camel.version>
</properties>
The exception is telling you that Spring Boot thinks you want to build a web server, but can't find the right dependencies on the classpath. The most obvious reason for that in your case would be that the HTTP dependencies you added included Servlet APIs. I see no reason why you need that for a client app, but only you would know whether you need it or not. Maybe you can exclude it?
If you do need the Servlet dependencies and just want to explicitly tell Boot that you aren't creating a web application you can set the property spring.main.web_environment=false, or use the SpringApplication (or SpringApplicationBuilder) API directly to set the same flag. See docs here for background information.

Jersey setup without web.xml

I'm attempting to set up a simple REST web application that uses Jersey. In the documentation, it seems that I should be able to create my application without using a web.xml file. From the site:
JAX-RS provides a deployment agnostic abstract class Application for declaring root resource and provider classes, and root resource and provider singleton instances. A Web service may extend this class to declare root resource and provider classes.
The example that follows shows this code:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorldResource.class);
return s;
}
}
To me, this says that I can use an Application class to do all of my servlet setup. This seems to be the configuration that reads my resource class's annotations and sets up the correct URL handling mechanisms. Is that correct? I don't have to do any other setup?
I ask because I created the following and it didn't work (I get a 404 from localhost:8080/{context}/test):
pom.xml:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
Application class:
#ApplicationPath("/")
public class JerseyTestApp extends Application
{
#Override
public Set<Class<?>> getClasses()
{
final Set<Class<?>> classes = new HashSet<>();
classes.add(JerseyTestController.class);
return classes;
}
}
Resource class:
#Path("/test")
public class JerseyTestController
{
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getTestMsg()
{
return "It works";
}
}
Dumb. All I had to do was include the jersey-servlet jar, as prescribed by this answer.

Resources