I want to set a simple response body from a spring webapp.
My problem is simple is given a web error.
My POM.xml is:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pt.dummy</groupId>
<artifactId>dummy</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>dummy Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
<tomcat.servlet.version>7.0.42</tomcat.servlet.version>
<log4j.version>1.7.5</log4j.version>
<java.version>1.7</java.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.servlet.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat.servlet.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>${tomcat.servlet.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-framework.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>dummy</finalName>
<testResources>
<testResource>
<!-- declared explicitly so Spring config files can be placed next to their corresponding JUnit test class
(see example with ValidatorTests) -->
<directory>${project.basedir}/src/test/java</directory>
</testResource>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
My web initializer is:
package dummy.web.config;
import javax.servlet.Filter;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { CoreConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] { characterEncodingFilter};
}
}
Core config:
package dummy.web.config;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CoreConfig {
}
Web Config:
package dummy.web.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"dummy.web.controller"})
public class WebConfig {
}
Site Controller:
package dummy.web.controller;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("/")
public class SiteController {
// private static final Logger LOG = LoggerFactory.getLogger(SiteController.class);
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String getHome() {
// LOG.debug("Home to ResponseBody");
return "Response Body";
}
}
Could anyone indicate the changes necessary to add to make this work?
I believe it is because of Tomcat. Most tutorials on the web put the spring mvc servlet directly in the application context. It never worked for me.
On Tomcat7 (even with XML configuration) you have to create two contexts: one for the overall app and one for spring web mvc. It has something to do with
#RequestMapping("/")
The server assigns "/" mapping to the default built-in servlet. Which is something you want him (or it or her) to do. But you also need Spring MVC to map "/".
Maybe they (the architects) thought springmvc is a specific servlet and shouldn't map the root contex. Instead, it should be under his own mapping (eg "/springmvc/"). And then it expects we have a real dispatcher which...dispatches between springmvc and whatever other servlets.
For some magical reason, in Tomcat 7.0.29 it wasn't even able to "dispatch" if you tried to hijack "/". On the recent version, mapping "/" works .But for this you need a separate web mvc context/root context.
I do not use AbstractAnnotationConfigDispatcherServletInitializer you have to translate the code below.
This was adapted from this tutorial on migrating from XML to Javaconfig spring-app-migration-from-xml-to-java-based-config
public class WebInit implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "spring-mvc";
private static final String DISPATCHER_SERVLET_MAPPING = "/";
#Override
public void onStartup(ServletContext servletContext)
throws ServletException {
//If you want to use the XML configuration, comment the following two lines out.
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(CoreConfig.class);
appContext.setDisplayName("removed customer name");
//If you want to use the XML configuration, uncomment the following lines.
//XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
//rootContext.setConfigLocation("classpath:mvc-servlet.xml");
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(ServletConfig.class);
ServletRegistration.Dynamic springmvc =
servletContext.addServlet(DISPATCHER_SERVLET_NAME,
new DispatcherServlet(mvcContext));
springmvc.setLoadOnStartup(1);
springmvc.addMapping(DISPATCHER_SERVLET_MAPPING);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
servletContext.addListener(new ContextLoaderListener(appContext));
}
Related
I am trying to write a simple 'hello world' application using Spring MVC.
My goal is to send a GET response and receive a text message, however it keeps returning 404 "The requested resource [/api/hello] is not available". What can potentially be wrong? Below is my code:
package org.example.rest.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/api")
public class MyRestController {
#GetMapping("/hello")
public String hello() {
return "Hello";
}
}
Config
package org.example.rest.configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.Properties;
#EnableWebMvc
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = "org.example.rest")
public class MyConfig {
#Bean
public DataSource dataSource() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/my_db?useSSL=false&serverTimezone=UTC");
dataSource.setUser("bestuser");
dataSource.setPassword("bestuser");
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactoryBean() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("org.example.rest.entity");
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
hibernateProperties.setProperty("hibernate.show_sql",
"true");
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager() {
HibernateTransactionManager manager = new HibernateTransactionManager();
manager.setSessionFactory(sessionFactoryBean().getObject());
return manager;
}
}
package org.example.rest.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MyConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-rest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.24.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
I am using IntelliJ IDEA 2022.2.2 (Ultimate Edition).
Server is Tomcat 9.0.71
I've been following this tutorial to learn how to develop a basic spring client and server application using wssecurity (certificates).
The demo works beautifully, but i need to deploy my application on a wildfly server, so i had to change the example a bit in order to avoid the embedded tomcat, the changes are as follows:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.spring.ws</groupId>
<artifactId>ws-security-certificate-wss4j-security-interceptor</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SPRING-WS - ${project.artifactId}</name>
<url>http://memorynotfound.com</url>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ws.security</groupId>
<artifactId>wss4j</artifactId>
<version>1.6.19</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/resources/xsd</source>
</sources>
<generatePackage>com.memorynotfound.beer</generatePackage>
</configuration>
</plugin>
</plugins>
</build>
RunServer.java
package com.memorynotfound.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication
public class RunServer extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(RunServer.class);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<RunServer> applicationClass = RunServer.class;
}
BeerEndpoint.java
package it.corvallis.soap.endpoint;
import com.memorynotfound.beer.Beer;
import com.memorynotfound.beer.GetBeerRequest;
import com.memorynotfound.beer.GetBeerResponse;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
#Endpoint
public class BeerEndpoint {
public static final String NAMESPACE_URI = "http://memorynotfound.com/beer";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBeerRequest")
#SoapAction("http://localhost:8080/ws/beers")
#ResponsePayload
public GetBeerResponse getBeer(#RequestPayload GetBeerRequest request) {
GetBeerResponse beerResponse = new GetBeerResponse();
Beer beer = new Beer();
beer.setId(request.getId());
beer.setName("Beer name");
beerResponse.setBeer(beer);
return beerResponse;
}
}
I deployed the server application on my wildfly and i tried to call it using the same client application used in the tutorial. The service seems to answer correctly, the beerResponse object is correctly istantiated, but, as soon as the object is being sent back to the the client, i see it's NULL.
What am i missing?
Thanks in advance
Oh well, next time i'll read better. At the same link of my first post, a guy asked the same question in the comments, here is the solution: add a callBackHandler to the client configuration, and modify the securityInterceptor to use this handler.
SoapClientConfig.java
package com.memorynotfound.client;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
import org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler;
import org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean;
import java.io.IOException;
#Configuration
public class SoapClientConfig {
#Bean
public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
// set security actions
securityInterceptor.setSecurementActions("Timestamp Signature Encrypt");
// sign the request
securityInterceptor.setSecurementUsername("client");
securityInterceptor.setSecurementPassword("changeit");
securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
// encrypt the request
securityInterceptor.setSecurementEncryptionUser("server-public");
securityInterceptor.setSecurementEncryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setSecurementEncryptionParts("{Content}{http://memorynotfound.com/beer}getBeerRequest");
// sign the response
securityInterceptor.setValidationActions("Signature Encrypt");
securityInterceptor.setValidationSignatureCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationDecryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationCallbackHandler(securityCallbackHandler());
return securityInterceptor;
}
#Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStorePassword("changeit");
cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("client.jks"));
return cryptoFactoryBean;
}
#Bean
public Jaxb2Marshaller getMarshaller(){
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.memorynotfound.beer");
return marshaller;
}
#Bean
public BeerClient getBeerClient() throws Exception {
BeerClient beerClient = new BeerClient();
beerClient.setMarshaller(getMarshaller());
beerClient.setUnmarshaller(getMarshaller());
beerClient.setDefaultUri("http://localhost:8080/ws/beers");
ClientInterceptor[] interceptors = new ClientInterceptor[]{securityInterceptor()};
beerClient.setInterceptors(interceptors);
return beerClient;
}
#Bean
public KeyStoreCallbackHandler securityCallbackHandler(){
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
callbackHandler.setPrivateKeyPassword("changeit");
return callbackHandler;
}
}
Here are my configuration classes::
In the templateResolver() method without ServletContext parameter i get compile error so add it as a parameter and give it to ServletContextTemplateResolver(servletContext);
#Configuration
#EnableWebMvc
#ComponentScan(basePackages= {"com.packtpub.springsecurity"})
public class ThymeleafConfig {
#Bean
public ServletContextTemplateResolver templateResolver(ServletContext servletContext) {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(1);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine(final ServletContextTemplateResolver templateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver);
return engine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver(final SpringTemplateEngine templateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine);
return resolver;
}
}
When i run my application i get following error:::
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method templateResolver in com.packtpub.springsecurity.web.configuration.ThymeleafConfig required a bean of type 'javax.servlet.ServletContext' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'javax.servlet.ServletContext' in your configuration.
What am i doing wrong?
thanks
Other config files are
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>chapter2</groupId>
<artifactId>chapter2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>chapter2</name>
<description>chapter 2 test</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring dependencies START-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!-- Servlet and JSP related dependencies -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- For datasource configuration -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<!-- We will be using MySQL as our database server -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- Spring dependencies END -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
#Configuration
//#Import({SecurityConfig.class, DataSourceConfig.class})
#ComponentScan(basePackages =
{
"com.packtpub.springsecurity.dataaccess",
"com.packtpub.springsecurity.domain",
"com.packtpub.springsecurity.service"
}
)
#PropertySource(value = {"classpath:application.properties"})
public class JavaConfig {
/**
* Note: If you want to use #PropertySource, you must create a static
* PropertySourcesPlaceholderConfigurer with the #Bean as seen here.
* #return PropertySourcesPlaceholderConfigurer
* #throws java.io.IOException
*/
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
propertySourcesPlaceholderConfigurer.setProperties(yamlPropertiesFactoryBean().getObject());
return propertySourcesPlaceholderConfigurer;
}
#Bean
public static YamlPropertiesFactoryBean yamlPropertiesFactoryBean() {
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
return yaml;
}
} // The end...
#Order(1)
public class SecurityWebAppInitializer
extends AbstractSecurityWebApplicationInitializer {
/**
* Don't initialize the filter directly, the Spring WebApplicationInitializer
* parent will take care of the initialization.
*/
public SecurityWebAppInitializer() {
super();
}
} // The end...
public class WebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { JavaConfig.class, SecurityConfig.class, DataSourceConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebMvcConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/*" };
}
#Override
public void onStartup(final ServletContext servletContext)
throws ServletException {
// Register DispatcherServlet
super.onStartup(servletContext);
// Register H2 Admin console:
ServletRegistration.Dynamic h2WebServlet = servletContext.addServlet("h2WebServlet",
"org.h2.server.web.WebServlet");
h2WebServlet.addMapping("/admin/h2/*");
h2WebServlet.setInitParameter("webAllowOthers", "true");
}
} // The End...
#Configuration
#EnableWebMvc
#Import({ThymeleafConfig.class})
#ComponentScan(basePackages = {
"com.packtpub.springsecurity.web.controllers",
"com.packtpub.springsecurity.web.model"
})
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
#Autowired
private ThymeleafViewResolver thymeleafViewResolver;
/**
* We mention this in the book, but this helps to ensure that the intercept-url patterns prevent access to our
* controllers. For example, once security has been applied for administrators try commenting out the modifications
* to the super class and requesting <a
* href="http://localhost:800/calendar/events/.html">http://localhost:800/calendar/events/.html</a>. You will
* observe that security is bypassed since it did not match the pattern we provided. In later chapters, we discuss
* how to secure the service tier which helps mitigate bypassing of the URL based security too.
*/
// FIXME: FInd out what this is and why it is here.
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping result = new RequestMappingHandlerMapping();
result.setUseSuffixPatternMatch(false);
result.setUseTrailingSlashMatch(false);
return result;
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/")
.setCachePeriod(31_556_926)
;
}
#Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
configurer
.ignoreAcceptHeader(false)
.favorPathExtension(true) // .html / .json / .ms
.defaultContentType(MediaType.TEXT_HTML) // text/html
.mediaTypes(
new HashMap<String, MediaType>(){
{
put("html", MediaType.TEXT_HTML);
put("xml", MediaType.APPLICATION_XML);
put("json", MediaType.APPLICATION_JSON);
}
})
;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
/*#Bean
public ContentNegotiatingViewResolver contentNegotiatingViewResolver() {
ContentNegotiatingViewResolver result = new ContentNegotiatingViewResolver();
Map<String, String> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE);
// result.setMediaTypes(mediaTypes);
result.setDefaultViews(Collections.singletonList(jacksonView()));
return result;
}*/
#Bean
public MappingJackson2JsonView jacksonView() {
MappingJackson2JsonView jacksonView = new MappingJackson2JsonView();
jacksonView.setExtractValueFromSingleKeyModel(true);
Set<String> modelKeys = new HashSet<String>();
modelKeys.add("events");
modelKeys.add("event");
jacksonView.setModelKeys(modelKeys);
return jacksonView;
}
#Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.viewResolver(thymeleafViewResolver);
}
// i18N support
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasenames("/WEB-INF/locales/messages");
resource.setDefaultEncoding("UTF-8");
resource.setFallbackToSystemLocale(Boolean.TRUE);
return resource;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
UPDATED
I have deleted the following dependencies from the POM according to #Adina in the comment below but still get the errors
<!-- dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency-->
What else can i do again
After some debugging on your code, the real problem is that you are autowiring ThymeleafViewResolver in the configuration responsible to configure servlet context.
public class WebMvcConfig implements WebMvcConfigurer{
#Autowired
private ThymeleafViewResolver thymeleafViewResolver;
The main problem is that before initializing your ServletContext, the application will try to initialize the ServletContextTemplateResolver (autowired will impose bean order initialization) and as you've noticed it depends on ServletContext.
Solution :
delete ThymeleafConfig class
don't autowire ThymeleafViewResolver in WebMvcConfig
and don't override method configureViewResolvers.
Don't worry, Thymeleaf will be set by default as the viewResolver.
Most of the config you've provided is already "taken care" by spring-boot-starter-thymeleaf.
If you want just to change default view directory resolver, you can just add in application.properties
spring.mvc.view.prefix=/WEB-INF/templates/
spring.mvc.view.suffix=.html
P.S: Take extra care when you override default definition from spring starters, as you can see these types of bugs are not easy to find.
Hello i am trying to implement swagger with Spring REST, i am not using Spring Boot to create REST API's, i have used normal Spring REST API.
The problem when i run the application and if i navigate to this url
http://localhost:8080/spring-mvc-restfull-crud-example/swagger-ui.html
i am getting only the header of swagger-ui, there is nothing else. I am using Java config instead of XML config.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.boraji.tutorial.spring</groupId>
<artifactId>spring-mvc-restfull-crud-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<!-- Spring MVC Dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.11.Final</version>
</dependency>
<!-- Hibernate-C3P0 Integration -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.2.11.Final</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
<!-- Jackson API for JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
<!-- Servlet Dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- this is for integrating swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>2.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Embedded Apache Tomcat required for testing web application -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
WebConfig.java
package com.boraji.tutorial.spring.config;
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.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.google.common.base.Predicates;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
BookController.java
package com.boraji.tutorial.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.boraji.tutorial.spring.model.Book;
import com.boraji.tutorial.spring.service.BookService;
import io.swagger.annotations.Api;
#CrossOrigin(origins = "*")
#RestController
public class BookController {
#Autowired
private BookService bookService;
/*---Add new book---*/
#PostMapping("/book")
public ResponseEntity<?> save(#RequestBody Book book) {
long id = bookService.save(book);
return ResponseEntity.ok().body("New Book has been saved with ID:" + id);
}
/*---Get a book by id---*/
#GetMapping("/book/{id}")
public ResponseEntity<Book> get(#PathVariable("id") long id) {
Book book = bookService.get(id);
return ResponseEntity.ok().body(book);
}
/*---get all books---*/
#GetMapping("/book")
public ResponseEntity<List<Book>> list() {
List<Book> books = bookService.list();
return ResponseEntity.ok().body(books);
}
/*---Update a book by id---*/
#PutMapping("/book/{id}")
public ResponseEntity<?> update(#PathVariable("id") long id, #RequestBody Book book) {
bookService.update(id, book);
return ResponseEntity.ok().body("Book has been updated successfully.");
}
/*---Delete a book by id---*/
#DeleteMapping("/book/{id}")
public ResponseEntity<?> delete(#PathVariable("id") long id) {
bookService.delete(id);
return ResponseEntity.ok().body("Book has been deleted successfully.");
}
}
In the resources folder, i have db.properties file
# MySQL properties
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/bookdb
mysql.user=root
mysql.password=root
# Hibernate properties
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
#C3P0 properties
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.acquire_increment=1
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=150
MyWebAppInitializer.java
package com.boraji.tutorial.spring.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
can you please anyone help me that what is wrong in this? is there anything that i need to add?
You have not defined Docket bean and neither you have used the #EnableSwagger2
The configuration of Swagger mainly centers around the Docket bean. Swagger 2 is enabled through the #EnableSwagger2 annotation. Refer the below code.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2).pathMapping("/data").apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo("ISW ADR Application",
"ADR or is another business line within the Issuer services business group."
+ "The primary functionalities of ADR are maintained within the DR system (mainframe) "
+ "Four main functionalities that are imported : "
+" 1) Dividend Announcements"
+ " 2) Depositary Service fees"
+ " 3) DR Fees"
+ " 4) DR Gross revenue.",
"ADR V2", "Terms of service", "xyz", "License of API", "API license URL");
}
}
You have not enabled swagger using #EnableSwagger2 and also have not returned a Docket Bean. Refer this.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket demoApi() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo"))
.paths(PathSelectors.regex("/person.*")).build();
}
}
I want to register a class component(Object) in jersey not class reference.
I create a XYZResource class that be called by main() method and it be configured through jersey with DBI object. DAOService daoService has connection DBI connection and the getDetails() that execute query and return result.
I use IntelliJ IDE and run through Main Class com.example.Main
when i hit my url http://localhost:9000/resource/test than it through error
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:
1. java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:392)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)
root cause
A MultiException has 1 exceptions. They are:
1. java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.
org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:88)
org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:852)
org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:174)
org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)
root cause
java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.
org.glassfish.jersey.internal.inject.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:189)
org.jvnet.hk2.internal.Utilities.getConstructor(Utilities.java:159)
org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:850)
org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:174)
org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)
Technology Use:
Java - 8
Embedded tomcat - 8
Jersey 2.5.1 (REST)
JDBI 2.63.1 (DB Service)
Main.java
package com.example;
import com.core.db.DAOService;
import com.example.servlets.HelloWorldServlet;
import com.example.util.abc;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.skife.jdbi.v2.DBI;
public class Main {
public static void main (String[] args) {
Tomcat tomcat = new Tomcat();
tomcat.setPort(9000);
String baseDoc = new File("src/main/webapp").getAbsolutePath();
Context ctx = tomcat.addContext("/servletSample", baseDoc);
tomcat.addWebapp(null, "", baseDoc);
tomcat.addServlet(ctx, "HelloWorld", new HelloWorldServlet());
ctx.addServletMapping("/*", "HelloWorld");
try {
final DBI XYZDBI = new DBI(/*url*/, /*username*/, /*password*/);
/* DAOService is a class that has function getDetails() that retrive data from database */
final DAOService daoService = XYZDBI.onDemand(DAOService.class);
final org.glassfish.jersey.server.ResourceConfig jerseyResource = new org.glassfish.jersey.server.ResourceConfig();
/* Register XYZResource class instance with jersey Resouce */
jerseyResource.register(new XYZResource(daoService));
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-jersey</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<finalName>my-embed-tomcat</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Dependencies for Jersey Web Application -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.42</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-jsp</artifactId>
<version>2.5.1</version>
</dependency>
<!-- Dependencies for Embedded Tomcat -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<!--org.skife.jdbi.v2-->
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
<version>2.63.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>microsoft.com</groupId>
<artifactId>sqlJdbc4</artifactId>
<version>4.0.2206.100</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
XYZResource.java
package com.example;
import com.core.db.DAOService;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;
#Path("resource")
public class XYZResource {
private final DAOService daoService;
public XYZResource(DAOService daoService) {
this.daoService = daoService;
}
#GET
public String helloworld() {
return "User - Resource";
}
#GET
#Path("/test")
public Response test() {
Set<String> User = daoService.getDetails();
Iterator<String> itr = User.iterator();
return Response.status(200).entity(itr.next().toString())
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET")
.build();
}
}
}
MyApplication.java
package com.example;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
public class MyApplication extends ResourceConfig {
public MyApplication() {
this.packages(MyApplication.class.getPackage().getName()).register(JspMvcFeature.class);
}
}
web.xml
<?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>Jersey Jersey Application</display-name>
<filter>
<filter-name>Jersey Application Filter</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.MyApplication</param-value>
</init-param>
<!-- pass to next filter if Jersey/App returns 404 -->
<init-param>
<param-name>jersey.config.servlet.filter.forwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Jersey Application Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Update
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>jersey-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<build>
<finalName>my-embed-tomcat</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<tomcat.version>8.0.28</tomcat.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
s
<dependency>
<groupId>org.glassfish.jersey.bundles.repackaged</groupId>
<artifactId>jersey-guava</artifactId>
<version>2.25.1</version>
</dependency>
<!-- Dependencies for Jersey Web Application -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-jsp</artifactId>
<version>2.5.1</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.5.1</version>
</dependency>
<!-- Dependencies for Embedded Tomcat -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<!--org.skife.jdbi.v2-->
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
<version>2.63.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.0.rc2</version>
</dependency>
<dependency>
<groupId>microsoft.com</groupId>
<artifactId>sqlJdbc4</artifactId>
<version>4.0.2206.100</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
Main.java
package com.example;
import org.apache.catalina.Context;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import javax.servlet.Filter;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.File;
/**
* #author Paul Samsotha.
*/
public class Main {
public static void main(String... args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(9000);
File base = new File(".");
Context context = tomcat.addContext("", base.getAbsolutePath());
Tomcat.addServlet(context, "default", new DefaultServlet());
context.addServletMapping("/*", "default");
final FilterDef def = new FilterDef();
final FilterMap map = new FilterMap();
def.setFilterName("jerseyFilter");
def.setFilter(getJerseyFilter());
context.addFilterDef(def);
map.setFilterName("jerseyFilter");
map.addURLPattern("/api/*");
context.addFilterMap(map);
tomcat.start();
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static Filter getJerseyFilter() {
final ResourceConfig config = new ResourceConfig()
.register(new HelloResource(new Service()))
.register(JspMvcFeature.class)
.property(ServletProperties.FILTER_FORWARD_ON_404, true);
return new ServletContainer(config);
}
public static class Service {
public String getMessage() {
return "Hello Tomcat!";
}
}
#Path("tomcat")
public static class HelloResource {
private final Service service;
public HelloResource (Service service) {
this.service = service;
}
#GET
public String get() {
return this.service.getMessage();
}
}
}
You seem to have a lot of unnecessary stuff going on. You have two different configurations. Pick one. The problem is caused by the package scanning, which is picking up the resource and trying to register it.
Just get rid of the web.xml and MyApplication and just use the ResourceConfig you're currently using in the main class. Then you can register the servlet programmatically using Jersey's ServletContainer which is both a Filter and a HttpServlet. So you don't need the web.xml to configure Jersey as Filter. The ServletContainer is already a Filter
new SevletContainer(youResourceConfig);
I'm not too familiar with Tomcat embedded so I can't say how to register filters, but I'm sure a quick search will find you the answer. Just register the ServletContainer as a filter.
The jersey.config.servlet.filter.forwardOn404 init-param can also be configured with the filter registration. Or you can just configure it with the ResourceConfig, with its property method
resourceConfig.property("jersey.config.servlet.filter.forwardOn404", true);
Or better yet, use the constant
property(ServletProperties.FILTER_FORWARD_ON_404, true);
UPDATE
Here is a complete setup (based on your example) that works.
import org.apache.catalina.Context;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import javax.servlet.Filter;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.File;
/**
* #author Paul Samsotha.
*/
public class Main {
public static void main(String... args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(9000);
File base = new File(".");
Context context = tomcat.addContext("", base.getAbsolutePath());
Tomcat.addServlet(context, "default", new DefaultServlet());
context.addServletMapping("/*", "default");
final FilterDef def = new FilterDef();
final FilterMap map = new FilterMap();
def.setFilterName("jerseyFilter");
def.setFilter(getJerseyFilter());
context.addFilterDef(def);
map.setFilterName("jerseyFilter");
map.addURLPattern("/api/*");
context.addFilterMap(map);
tomcat.start();
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static Filter getJerseyFilter() {
final ResourceConfig config = new ResourceConfig()
.register(new HelloResource(new Service()))
.register(JspMvcFeature.class)
.property(ServletProperties.FILTER_FORWARD_ON_404, true);
return new ServletContainer(config);
}
public static class Service {
public String getMessage() {
return "Hello Tomcat!";
}
}
#Path("tomcat")
public static class HelloResource {
private final Service service;
public HelloResource (Service service) {
this.service = service;
}
#GET
public String get() {
return this.service.getMessage();
}
}
}
A few changes I made:
Not sure why you are using Tomcat 7 Servlet API. I Changed that to the 8.x version of your other Tomcat dependencies.
I also excluded the Servlet API from the Jersey MVC dependency, as that pulls in an older 2.4 Servlet API
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-jsp</artifactId>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
I added a DefaultServlet to handle the pages. From testing (again I am not Tomcat expert), it seems this is required
With the example you should be able to GET
http://localhost:9000/api/tomcat
First, Thanks to peeskillet who solved my problem. I search on the net but I did not find the exact solution.
For better reference and understandability, I create a demo application on git-hub.
jersey-mvc-jsp-freemarker-with-embedded-tomcat
Application Used
Tomcat v8.x
Jersey v2.5.1
JSP
YML
Freemarker
HTML/Angular/JavaScript
final ResourceConfig config = new ResourceConfig()
.packages(Main.class.getPackage().getName())
.register(new Resource(new Core(), configuration)) // create instance of Resource and dynamically register
.register(JspMvcFeature.class) // register jspMVC
.register(FreemarkerMvcFeature.class) // register FreemarkerMVC
.property(ServletProperties.FILTER_FORWARD_ON_404, true);
return new ServletContainer(config);