No injection source found for Multipart feature - maven

when I try to deploy my maven project to Glassfish 5, I get the following error:
[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response com.test.Resources.AccountResource.addProfilePicture(java.io.InputStream,org.glassfish.jersey.media.multipart.FormDataContentDisposition) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[multipart/form-data], producedTypes=[], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.test.Resources.AccountResource, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#1efcbc1f]}, definitionMethod=public javax.ws.rs.core.Response com.test.Resources.AccountResource.addProfilePicture(java.io.InputStream,org.glassfish.jersey.media.multipart.FormDataContentDisposition), parameters=[Parameter [type=class java.io.InputStream, source=profilePicture, defaultValue=null], Parameter [type=class org.glassfish.jersey.media.multipart.FormDataContentDisposition, source=profilePicture, defaultValue=null]], responseType=class javax.ws.rs.core.Response}, nameBindings=[]}']. Please see server.log for more details.
This is the code which causes the troubles:
#POST
#Path("addProfilePicture")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response addProfilePicture(#FormDataParam("profilePicture") InputStream pic,
#FormDataParam("profilePicture") FormDataContentDisposition formDataContentDisposition){
return Response.ok().build();
}
my web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.test</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
According to similar answers, I should add the maven dependency and register the MultiPartFeature.
As you can see, I did both.
#ApplicationPath("/")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> classes = new HashSet<>();
classes.add(MultiPartFeature.class);
System.out.println("added multipart feature");
classes.add(AccountResource.class);
return classes;
}
}
and here are my maven dependencies:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
I already tried to change the scope to provided and used ResourceConfig instead of Application.

So here's the thing. You have two different application configurations: the web.xml and the ApplicationConfig class. These are to completely separate configurations, which are both valid all by themselves. The ApplicationConfig class is the one that registers the MultiPartFeature, but it seems like the configuration that is being used is the web.xml. I never really tested what happens when you have two different application configurations, but it seems like your web.xml is taking precedence. And in your web.xml, you are not configuring the MultiPartFeature.
If you want to just use the web.xml, then you can check out this answer for how out can configure it.
You can however just delete the entire web.xml. This will cause the ApplicationConfig to kick it. But notice the two differences: the #ApplicationPath on the ApplicationConfig acts like the url-mapping in the web.xml. So if you delete the web.xml, then the base path will just be / (or nothing) instead of the /webapi like you have in the web.xml
If you decide the delete the web.xml, I suggest you use ResourceConfig instead of Application. You can get some good information about this class and different configuration possibilities in this post from What exactly is the ResourceConfig class in Jersey 2?

Related

JAVA Migration from jdk1.7 and weblogic 12c to jdk 1.8 and weblogic 14c

i ve migrate a web application from weblogic 12c and jdk1.7 to weblogic 14c and jdk1.8. The web application use jax-re for rest services and has the following custom JacksonContextProvider for mapping json:
package eu.sia.mdp.backoffice.common;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
/**
* ObjectMapper settings
*
* #author g.palladino
*
*/
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
private static final Logger log = LoggerFactory.getLogger( JacksonContextResolver.class );
public JacksonContextResolver() {
this.objectMapper = new ObjectMapper().setSerializationInclusion(Include.NON_NULL);
// DATEFORMAT DF = NEW SIMPLEDATEFORMAT("YYYY-MM-DD HH:MM:SS.SSSZ");
// this.objectMapper.setDateFormat(df);
this.objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
this.objectMapper.getSerializationConfig().getDateFormat().setTimeZone(TimeZone.getTimeZone("CET"));
}
#Override
public ObjectMapper getContext(Class<?> objectType) {
return null;
}
}
the application, for the webservices, use the jax-rs 2.0.1 and jersey 2.29 provided by server weblogic 14.1.1 (14c). In version built with jdk1.7 and deployed on server weblogic 12c the libraries was not provided by the server but put in pom file without scope provided and the custom ContextResolver was worked fine. Now, with provided libraries, the custom ContextResolver is completely ignored and the webservices return json in a format that is not as i want, for example the dates was in the format 'yyyy-MM-ddTHH:mm:ss.SSSZ' (2022-12-16T11:33:21.123 0100' and now I receive the dates in the format 'yyyy-MM-ddTHH:mm:ss.SSSZ [UTC]' (2022-12-16T11:33:21.123Z [UTC]) and if pass this date to a rest service in my application i have the type mismatch error. Seems that is used the server's ObjectMapper.
could someone help me figure out how to configure the weblogic.xml and/or web.xml files to pass the jax-rs and jersey libraries without provided scope in order to then use the custom ObjectMapper in the class JacksonContextResolver implements ContextResolver ObjectMapper and not the server ObjectMapper???
the current server is Weblogic 14.1.1.
pom file:
<!-- JAX-RS -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<!--<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>-->
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
<version>${jersey.version}</version>
<scope>provided</scope>
</dependency>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false">
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>eu.sia.mdp.backoffice</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.tracing</param-name>
<param-value>ALL</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>json</extension>
<mime-type>application/json</mime-type>
</mime-mapping>
<resource-ref>
<description>Database MP</description>
<res-ref-name>jdbc/MPDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
weblogic.xml
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="...">
<container-descriptor>
<prefer-application-packages>
<package-name>org.slf4j.*</package-name>
<package-name>org.apache.commons.logging.*</package-name>
<package-name>com.sun.jersey.*</package-name>
<!--<package-name>org.glassfish.jersey.*</package-name>
<package-name>org.glassfish.hk2.*</package-name>-->
<package-name>org.jvnet.hk2.*</package-name>
<!--<package-name>jersey.repackaged.org.objectweb.asm.*</package-name>-->
<package-name>org.objectweb.asm.*</package-name>
<package-name>com.sun.ws.rs.ext.*</package-name>
<!--<package-name>javax.ws.rs.*</package-name>
<package-name>javax.validation.*</package-name>-->
<package-name>org.hibernate.validator.*</package-name>
</prefer-application-packages>
<prefer-application-resources>
<resource-name>org/slf4j/impl/StaticLoggerBinder.class</resource-name>
<resource-name>org.hibernate.validator.*</resource-name>
<resource-name>javax.validation.*</resource-name>
</prefer-application-resources>
</container-descriptor>
<context-root>mdp-portale-bo</context-root>
<library-ref>
<library-name>jax-rs</library-name>
<specification-version>2.0</specification-version>
<exact-match>false</exact-match>
</library-ref>
<resource-description>
<res-ref-name>jdbc/MDPDB</res-ref-name>
<jndi-name>jdbc/MDPDB</jndi-name>
</resource-description>
</weblogic-web-app>
Thanks

OpenAPI add server at Server Start

I try to modify server list (or default server) on Swagger UI.
1/ On Spring (Not Spring Boot) configuration class I add this :
#Bean
public OpenAPI customOpenAPI() {
log.info("<<<customOpenAPI>>>");
Server server = new Server();
server.setUrl("http://localhost:8091/eatery_spring_rs/rs/");
return new OpenAPI()
.servers(List.of(server));
}
2/ But I never obtain result on Swagger UI, no server is added :
3/ Maven dependencies are :
<!--SWAGGER-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.7</version>
</dependency>
<!-- END -->
5/ Question :
Is it possible to change context path, or add server URL, by program ?
6/ I can affine the description of problem
The context path of application is not complete
It is a Spring 5.3 application, start with web.xml in App Server.
like Tomcat, ...
This is the web.xml definition :
`
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:servlet-service.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/rs/*</url-pattern>
</servlet-mapping>`
This mean that the real context path is : [app.context]/rs but in the case of :
#Bean public Docket api(ServletContext servletContext) {
servletContext is equal to [app.context] NOT to [app.context]/rs
It's help ?

Multiple Contexts For Request Scope?

I am attempting to use Weld with Tomcat7 and Jersey, and in my log files I am seeing this:
org.jboss.weld.exceptions.IllegalStateException: WELD-001304: More than one context active for scope type javax.enterprise.context.RequestScoped
The application deploys properly and I only see this when attempting to hit on my Jersey endpoints.
Here is the pertinent parts of the pom.xml
<!-- Jersey Deps -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<!-- CDI Deps -->
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>2.3.2.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-weld2-se</artifactId>
</dependency>
And here's my "MainApplication" that extends ResourceConfig:
public class MainApplication extends ResourceConfig {
public MainApplication() {
packages(true, "com.example.api");
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
}
}
Here's my web.xml (the servlet section):
<servlet>
<servlet-name>Jersey Servlet Container</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>net.di2e.isfr.foldr.MainApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Servlet Container</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
I am uber-confsued what could be going wrong.

JSP file not rendering in Spring Boot web application

I have a Spring Boot web application up and running using embedded Tomcat (the default). When it serves up JSP files as part of rendering the view I specified in my controller, the JSPs are not being rendered as such, and instead print out the contents. For example:
index.jsp
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>Test</body>
</html>
When the view is rendered in the browsers, the contents above are displayed, instead of the expected contents:
Test
Make sure that your pom.xml specifies the Tomcat JSP dependency as follows:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
It seems that embedded Tomcat treats the JSP rendering as optional.
As mentioned below, this JAR is sometimes necessary as well:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>provided</scope>
</dependency>
(I added provided since this JAR should be included by the servlet container.
You will need not one but two dependencies (jasper and jstl) in your pom.xml for this to work.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
For me worked the same like Dan mentioned. Removing the provided scope.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Thanks guy's!
Worked for me too but, I had to remove
<scope>provided</scope>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
Better you can use gradle (which is catching up over Maven). Use this dependency in build.gradle file.
//Required dependency for JSP
providedRuntime 'org.apache.tomcat.embed:tomcat-embed-jasper'
Make sure, spring-boot-starter-tomcat, tomcat-embed-jasper and jstl dependencies are in the pom.xml.
Make sure the packaging type is war.
If there are multiple modules (IntelliJ), go into Run -> Edit configuration -> Configuration, and select or put $MODULE_WORKING_DIR$ in the 'Working directory'.
That's it.
I think you missed some configuration because it is easy to integrate JSP just follow below steps
1 - tomcat-embad-jasper dependency
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
2 - Add below configuration is application.properties
spring.mvc.view.prefix: /
spring.mvc.view.suffix: .jsp
That's it still have some doubt then check it out below link
Spring Boot and JSP Integration
The reason is because you are using the annotation #RestController instead of #Controller
When you annotate a class with RestController, all methods annotated with #RequestMapping assume #ResponseBody semantics by default. In other words, your method #index is serializing the String /webapp/WEB-INF/index.jsp as JSON, instead of mapping its value to a view.
Like mentioned in one of the answers, it has to be
#Controller
public class YourController {
...
}
I resolved my issue when in addition to described before:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
added ViewResolver:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#ComponentScan
#EnableWebMvc
public class SpringServletConfig {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
}
from: Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
Just change the dependency
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
to
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
Full gradle setup for Spring-Boot with Spring-MVC and with embedded Tomcat server:
build.gradle
buildscript {
ext {
springBootVersion = '1.5.8.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
//WEB-MVC
compile 'org.springframework.boot:spring-boot-starter-web:1.5.8.RELEASE'
compile 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.1'
compile 'javax.servlet:jstl:1.2'
App.class
#SpringBootApplication
public final class App {
public static void main(final String[] args) {
new SpringApplicationBuilder(App.class)
.build(args)
.run();
}
#Bean
public ViewResolver viewResolver() {
final InternalResourceViewResolver r = new InternalResourceViewResolver();
r.setPrefix("/WEB-INF/jsp/");
r.setSuffix(".jsp");
return r;
}
}
You need jsp compiler jar (tomcat-jasper) in class-path. Embedded tomcat does not come with it.
Remove tomcat-embed-jasper.jar if added already and add below
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.1</version>
</dependency>
As seen Spring and Spring Boot has been changing, here is an up-to-date solution.
build.gradle:
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.0.RELEASE'
compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.0.35'
}
IndexController.java looks as follows:
#Controller
public class IndexController {
#RequestMapping("/index")
public String index(Model model) {
model.addAttribute("name", "jancsi");
return "index";
}
}
WebConfig.java:
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Here, instead of using WebMvcConfigurerAdapter, you should use WebMvcConfigurer interface, and do not to forget to enalbe the default servlet hander.
And then the structure of folders of jsp files.
src/main/webapp
└── WEB-INF
└── views
└── index.jsp
Sometimes tomcat-embed-jasper not available so need to remove provided from the maven dependency of tomcat-embed-jasper.
eg.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--scope>provided</scope-->
</dependency>
If you want to use 1.5.8.RELEASE or similar, then, runable example and its explanation is in here https://www.surasint.com/spring-boot-jsp/
You just need this in pom.xml
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.8.RELEASE
<groupId>com.surasint.example</groupId>
<artifactId>spring-boot-02</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- jstl for jsp -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
And this in application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Then you keep your jsp in the /WEB-INF/jsp/ folder.
This is the controller.
package com.surasint.example.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Date;
import java.util.Map;
#Controller
public class TestController {
#GetMapping("/testjsp")
public String list(Map<String, Object> model) {
model.put("this_time",new Date().toString());
return "testjsp-view";
}
}
I had this problem and finally resolved it!
My problem was that I had been putting JSP code in my /WEB-INF/index.jsp page. However, this page is served directly, without being processed by any servlet or controller. Therefore, it had no chance of being compiled.
My solution:
Move index.jsp into a subfolder called views.
Edit web.xml so that it passes control of the root directory to the dispatcher servlet.
<!-- WEB-INF/web.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>18-655_lab_1</display-name>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Edit dispatcher-servlet.xml to ensure that it's looking in the views directory for files ending in .jsp.
<!-- WEB-INF/dispatcher-servlet.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven />
<context:component-scan
base-package="com.app.controller" />
<mvc:default-servlet-handler />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Using the same base-package path as specified in dispatcher-servlet.xml, create controller that will return a ModelAndView.
package com.app.controller;
#Controller
#RequestMapping(value = "/")
public class RootController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView homeGet() {
return new ModelAndView("index", "message", "IT WORKS!!!");
}
}
The syntax new ModelAndView("index", "message", "IT WORKS!!!") means that
dispatcher-servlet looks for a file called "/WEB-INF/views/" + "index" + ".jsp".
It compiles the jsp file, replacing all instances of ${message} with IT WORKS!!!.
Therefore, the final thing to do is to put ${message} somewhere in our index.jsp file.
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>${message}</h1>
</body>
</html>
Load the project into your Tomcat server, start it, and go to http://localhost:8080/[project name]/.
For me with Spring Boot version 1.5.10.RELEASE, it worked on adding below maven dependencies.
Note: worked only on not providing the <scope> for these two.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--<scope>provided</scope>-->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<!--<scope>provided</scope>-->
</dependency>
And providing below configuration in application.properties file
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
I faced the issue like printed the jsp file name in the browser instead of its contents.
By adding the below snippet for jsp page rendering in pom.xml , it renders properly.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherSe rvlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I took the * off so it was just from web.xml
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherSe rvlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Please consider, there are some JSP Limitations. You can not set the packaging of your pom to jar. Read this JSP Limitations

Spring DI - Autowired property is null in a REST service

I'm getting started with Spring DI, but I'm struggling with dependency injection and the worse part is that I'm not even sure why as it seems ok to me. Hopefully you guys can help me out!
The problem is that a property annotated as #Autowired is always null
I've got a few projects with Maven structure:
com.diegotutor.lessondeliver
com.diegotutor.utility
I'm running the examples over Tomcat 7
I'm using the following dependencies in my pom.xml:
spring-context 3.2.4
spring-web 3.2.4
jersey-server 1.17.1
jersey-core 1.17.1
jersey-servlet 1.17.1
The simple idea is to have a RESTful service that through Dependency Injection is able to print out the value of a property located in a config file located at: D:\configuracion.conf.
At com.diegotutor.utility I have the following interface:
package com.diegotutor.utility;
public interface ConfigService {
public String getProperty(final String propertyName);
}
Implemented by:
package com.diegotutor.utility.impl;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import com.diegotutor.utility.ConfigService;
public class PropertyFileConfigService implements ConfigService{
Properties prop;
public PropertyFileConfigService (final InputStream input) throws IOException {
if(input == null) {
throw new IllegalArgumentException("Input stream can't be null");
}
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService (final String fileName) throws IOException {
final FileInputStream input = new FileInputStream(fileName);
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService(final Reader input) throws IOException {
prop = new Properties();
prop.load(input);
}
public String getProperty(final String propertyName) {
return prop.getProperty(propertyName);
}
}
And at com.diegotutor.lessondeliver I have the RESTful service where I would like to use an injected instance of the ConfigService:
package com.diegotutor.lessondeliver;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.diegotutor.utility.ConfigService;
#Path("/")
#Component
public class HelloWorld {
private static final Log log = LogFactory.getLog(HelloWorld.class);
#Autowired
private ConfigService configService;
#Path("/helloworld")
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getHello() {
String host = configService.getProperty("host");
return "Hello World! HOST" + host;
// configService IS NULL!!
//SO IT THROWS A NULLPOINTER EXCEPTION WHEN INVOKING getProperty ON IT
}
}
Finally at /com.diegotutor.lessondeliver/src/main/webapp/WEB-INF/service-beans.xml I have the following XML application context file, where I use the implementation of ConfigService (PropertyFileConfigService) injecting on it the path for the configuration file to read:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="configService" class="com.diegotutor.utility.impl.PropertyFileConfigService">
<constructor-arg type="java.lang.String"
value="D:\configuracion.conf" />
</bean>
<context:component-scan base-package="com.diegotutor" />
</beans>
Obviously I have specified in the web.xml of this com.diegotutor.lessondeliver web app that I want service-beans.xml as ConfigLocation and a listener ContextLoaderListener, and the RESTful service relies on ServletContainer
If I'm specifying context:component-scan to look for Components in com.diegotutor as suggested here and I'm forcing object creation through Spring by not using any new Statement as suggested here, Why am I getting the annotated configService as null? Why Spring is unable to inject an instance of com.diegotutor.utility.impl.PropertyFileConfigService?
Any help will be much appreciated!
Thank you
EDITED:
As requested, my web.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>com.diegotutor.lessondeliver</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/service-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
You were right!
It seems that the problem is that Jersey is totally unaware of Spring and instantiates its own object. In order to make Jersey aware of Spring object creations (through dependency injection) I had to integrate Spring + Jersey.
To integrate:
Add maven dependencies
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.17.1</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
Use SpringServlet for jersey-servlet in web.xml
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Now the #Autowired works properly and the object is not null anymore.
I'm a little bit confused about the exclusions I have to use in maven when using jersey-spring dependency, but that's another issue :)
Thank you!
Integration Spring with Jersey 2 (org.glassfish.*):
Maven
Some dependencies may be unnecessary, please check & clear it after things got working.
<properties>
<jersey.version>2.5</jersey.version>
</properties>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<!-- if your container implements Servlet API older than 3.0, use "jersey-container-servlet-core" -->
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
web.xml
<servlet>
<servlet-name>my-rest-service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package.with.rest.services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-rest-service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
During the Spring upgrading I had to move it from /main/webapp/WEB-INF/ to /main/resources/ (details).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="my.package.with.rest.services" />
</beans>
Example REST service
public interface MyService
{
String work(String s);
}
...
#Service
public class MyServiceImpl implements MyService
{
#Override
public String work(String s)
{
return "Hello, " + s;
}
}
...
#Path("demo/")
#Component
public class DemoRestService
{
#Autowired
private MyService service;
#GET
#Path("test")
public Response test(#FormParam("param") String par)
{
try
{
String entity = service.work(par);
return Response.ok(entity).build();
}
catch (Exception e)
{
e.printStackTrace();
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Epic REST Failure").build();
}
}
}
or you can simply extend SpringBeanAutoWiringSupport class. Like this: public class DemoRestService extends SpringBeanAutoWiringSupport. By extending this support class, properties of your service class can be auto-wired.
Another possible option is to manually invoke autowiring in your jersey resource:
#Context
private ServletContext servletContext;
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}
Hmm, you get a "manual autowiring"...

Resources