I am converting my camel spring application to use spring boot latest version 1.4.0.
My application context xml is outside my WAR , to add flexibility. But I am unable to get it loaded in the project. If I add it inside my project classpath and use #ImportResource it works fine. How do i Get it loaded from outside.
My web.xml (old one)
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>file:///${camel.config.location}</param-value>
<description> location of spring xml files</description>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>file:///${log4j.config.location}</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>10000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
</web-app>
I have implemented the below application class after searching thru a example but the context.xml is not loaded . I have added it as a resource Loader. I used onStartup too but still noting gets loaded only spring boot loads up.
#Configuration
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#ComponentScan
public class DLBootApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
final ConfigurableEnvironment environment = new StandardServletEnvironment();
initialize(environment);
final ResourceLoader resourceLoader = createResourceLoader();
final ApplicationContext ctx = new SpringApplicationBuilder(DLBootApplication.class)
.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class).environment(environment)
.resourceLoader(resourceLoader).run(args);
}
public static void initialize(ConfigurableEnvironment environment) {
final String camelConfig = environment.getProperty(Constants.DL_CAMEL_CONFIG_LOCATION);
final String log4jConfig = environment.getProperty(Constants.DL_LOG4J_CONFIG_LOCATION);
if (StringUtils.isEmpty(camelConfig)) {
throw new IllegalStateException(Constants.DL_CAMEL_CONFIG_LOCATION + " is empty");
}
if (StringUtils.isEmpty(log4jConfig)) {
throw new IllegalStateException(Constants.DL_LOG4J_CONFIG_LOCATION + " is empty");
}
System.setProperty(Constants.DL_CAMEL_CONFIG_LOCATION, camelConfig);
System.setProperty(Constants.DL_LOG4J_CONFIG_LOCATION, log4jConfig);
}
public static ResourceLoader createResourceLoader() {
final FileSystemResourceLoader resLoader = new FileSystemResourceLoader();
resLoader.getResource(System.getProperty(Constants.DL_CAMEL_CONFIG_LOCATION));
return resLoader;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
final ConfigurableEnvironment environment = new StandardServletEnvironment();
initialize(environment);
final ResourceLoader resourceLoader = createResourceLoader();
return application.sources(DLBootApplication.class).environment(environment).resourceLoader(resourceLoader);
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(DLBootApplication.class);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.addListener(new Log4jConfigListener());
}
}
got it working using #Importresorce and the file location from a environment variable.
I have a strange behaviour with a Spring Data Rest implementation (version 2.5.2.RELEASE).
I'm trying to register a #Bean of ResourceProcessor<Resource<Entity>>, but there is something strange.
I'm trying with two kinds of solutions:
1) Declaring the #Bean in a class:
#Bean
public ResourceProcessor<Resource<Author>> authorProcessor() {
return new ResourceProcessor<Resource<Author>>() {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of bean ResourceProcessor of class RepositoryBaseConfiguration");
return resource;
}
};
}
2) Implementing the interface ResourceProcessor:
#Component
public class AuthorResourceProcessor implements ResourceProcessor<Resource<Author>> {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of class AuthorResourceProcessor");
return resource;
}
}
The processors are completely ignored: the message is never printed.
I noticed that the class org.springframework.data.rest.webmvc.ResourceProcessorInvoker has a constructor:
public ResourceProcessorInvoker(Collection<ResourceProcessor<?>> processors) {
//...
}
This constructor is invoked 2 times at the start of the application instead of only one time (as I will expect), and I don't understand why.
The first time, the "processors" variable is solved with the two beans (as expected) and with the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
But the second time, the "processors" variable is solved with only the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
The second configuration #Override the first one.
Any idea?
The problem depends on the configurations loaded at the startup of the application.
I had this configuration on the web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-web-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.data.rest.webmvc.RepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
So, the ContextLoaderListener loaded the correct configuration in the first time; the "load-on-startup" property of the servlet "RepositoryRestDispatcherServlet" launch a second context configuration load.
I also had a custom class that extended org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration, but this custom class was ignored by the moment that the constructor of RepositoryRestDispatcherServlet load the default RepositoryRestMvcConfiguration, causing the lost of the configurations.
To solve that issue I have created a custom RepositoryRestDispatcherServlet in this way:
public class AppRepositoryRestDispatcherServlet extends DispatcherServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public AppRepositoryRestDispatcherServlet() {
configure();
}
public AppRepositoryRestDispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
configure();
}
private void configure() {
setContextClass(AnnotationConfigWebApplicationContext.class);
setContextConfigLocation(RepositoryBaseConfiguration.class.getName());
}
}
The class is the same as RepositoryRestDispatcherServlet, with the only difference that in the setContextConfigLocation is passed the custom class that extends RepositoryRestMvcConfiguration (RepositoryBaseConfiguration in this example).
Obviously I had to update the web.xml as follows:
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>my.package.AppRepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
In this way, the configuration is correctly loaded and mantained.
Hate to ask a simple config question but I'm new to the spring mvc framework and for some reason struggling a little bit. I am working on this just to learn it as I have used MVC in ruby and wanted to try it in java.
I have a sample app that talks to a DB and returns a full table from my controller out to a JSP it all works my table is displaying from the DB Correctly. I still think I have my configs wrong though as my app only works if my web.xml is setup like so
<servlet-mapping>
<servlet-name>foo</servlet-name>
<url-pattern>/RunList.jsp</url-pattern>
</servlet-mapping>
I don't think I should have to use the full name of the JSP in my pattern. if I just use / I get
<servlet-mapping>
<servlet-name>foo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Sep 01, 2015 10:53:02 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/dyn-qa-qeb/] in DispatcherServlet with name 'foo'
Here is my controller
#RequestMapping(value="/RunList")
public ModelAndView listRun(ModelAndView model) throws IOException{
//#ModelAttribute
System.out.println("**** Controller ******");
List<QAModel> listRun = runDao.list();
model.addObject("RunList", listRun);
model.setViewName("RunList");
return model;
}
I also have an MVC Configuration file that I setup based on a tutorial but I am not sure if that just overrides the web.xml
#Configuration
#ComponentScan(basePackages="com.foo")
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
This was a config issue long ago solved just cleaning up my questions
In my Spring Boot application with packaging type as war, i am configuring Spring MVC. As i understand we dont have to configure Dispatcher Servlet Manually. However, i old style of web.xml i used to configure Dispatcher Servlet and then i used to pass contextClass and contextConfigLocation as follows
<servlet>
<description>
</description>
<display-name>DispatcherServlet</display-name>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>contextClass</description>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<description>contextConfigLocation</description>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I belive this was to indicate that SpringMvcConfig (my custom class with spring mvc configuration) is the configuration class for Spring MVC..
However, In spring boot if Dispatcher Servlet is configured Automatically, how can i pass my custom class to dispatcher Servlet ?
In my Spring Boot application, my SpringMvcConfig class extends from WebMvcConfigurerAdapter and is annotated with #Configuration class
Help Needed...
Right in the configuration class which is annotated by #Configuration you could define your dispatcherServlet and pass init-parameter to it.
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(dispatcherServlet());
registrationBean.addInitParameter("contextClass","org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
registrationBean.addInitParameter("contextConfigLocation","com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig");
return registrationBean;
}
Another way would be to create a paramter map and then set parameter for registration bean. This stream shows how to do it.
I think you have to create a config class as follow:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { DemoAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
I have two servers (Apache and JBoss AS7) and I need to provide access to all http methods to a client. All these request must be sent via ajax.
Example of the client code:
$.ajax({
type: "get",
url: "http://localhost:9080/myproject/services/mobile/list",
crossDomain: true,
cache: false,
dataType: "json",
success: function(response) {
console.log(response);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
console.log(jqXHR.responseText);
console.log(errorThrown);
}
});
In JBoss AS7 I'm using RESTEasy, implementing CORS as follows:
#Path("/mobile")
#Provider
#ServerInterceptor
public class GroupMobile implements MessageBodyWriterInterceptor {
#Inject
private GroupDAO groupDAO;
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public List<Group> getGroups() {
return groupDAO.listAll();
}
#Override
public void write(MessageBodyWriterContext context) throws IOException,
WebApplicationException {
context.getHeaders().add("Access-Control-Allow-Origin", "*");
context.proceed();
}
#OPTIONS
#Path("/{path:.*}")
public Response handleCORSRequest(
#HeaderParam("Access-Control-Request-Method") final String requestMethod,
#HeaderParam("Access-Control-Request-Headers") final String requestHeaders) {
final ResponseBuilder retValue = Response.ok();
if (requestHeaders != null)
retValue.header("Access-Control-Allow-Headers", requestHeaders);
if (requestMethod != null)
retValue.header("Access-Control-Allow-Methods", requestMethod);
retValue.header("Access-Control-Allow-Origin", "*");
return retValue.build();
}
}
web.xml and beans.xml are empty files.
When I access MyIP:8080 (Apache), I get the error message:
XMLHttpRequest cannot load http://localhost:9080/myproject/services/mobile/list?_=1359480354190. Origin http://MyIP:8080 is not allowed by Access-Control-Allow-Origin.
Does anybody know what is wrong?
The newest resteasy (3.0.9-Final) include a utility class org.jboss.resteasy.plugins.interceptors.CorsFilter.
You can add the CorsFilter object into Application's singleton
objects set, or add it into ProviderFactory in ResteasyDeployment
directly.
The following is the sample application class:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;
#ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
Set<Object> singletons;
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> clazzes = new HashSet<>();
clazzes.add(VersionService.class);
return clazzes;
}
#Override
public Set<Object> getSingletons() {
if (singletons == null) {
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().add("*");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
return singletons;
}
}
The problem you are having is your are trying to do cross-site scripting. You accessed the page at http://MyIP:8080 and so the browser is preventing you from accessing resources outside that domain. This is very browser specific and browser based work arounds will all be different (you can disable security in Chrome globally, and on a per site basis in IE).
If you load the page as http://localhost:8080, it should then allow you access the query. Alternatively, you can implement a proxy which will forward the request.
Sounds like the issue is related to https://issues.jboss.org/browse/RESTEASY-878. You may not be able to catch CORS preflight requests with MessageBodyWriterInterceptor. Try using servlet filters (#WebFilter) instead.
Well, I have implemented a small solution, first I do a interceptor in my project Web
I created a class called "CORSInterceptor" the class is of the way.
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.MessageBodyWriterContext;
import org.jboss.resteasy.spi.interception.MessageBodyWriterInterceptor;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
#Provider
#ServerInterceptor
public class CorsInterceptor implements PreProcessInterceptor, MessageBodyWriterInterceptor {
/**
* The Origin header set by the browser at each request.
*/
private static final String ORIGIN = "Origin";
/**
* The Access-Control-Allow-Origin header indicates which origin a resource it is specified for can be
* shared with. ABNF: Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" source origin string | "*"
*/
private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
//
private static final ThreadLocal<String> REQUEST_ORIGIN = new ThreadLocal<String>();
//
private final Set<String> allowedOrigins;
public CorsInterceptor(){
this.allowedOrigins = new HashSet<String>();
this.allowedOrigins.add("*");
}
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException {
if (!allowedOrigins.isEmpty()) {
REQUEST_ORIGIN.set(request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN));
}
return null;
}
#Override
public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException {
if (!allowedOrigins.isEmpty() && (allowedOrigins.contains(REQUEST_ORIGIN.get()) || allowedOrigins.contains("*"))) {
context.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN, REQUEST_ORIGIN.get());
}
context.proceed();
}
}
In the File Web.xml, I add it
<context-param>
<param-name>resteasy.providers</param-name>
<param-value><package>.CorsInterceptor</param-value>
</context-param>
package: Ubication of the class.
Request JQuery that I have used.
$.ajax({
type: 'GET',
dataType: "json",
crossDomain : true,
cache:false,
url: "http://localhost:12005/ProyectoWebServices/ws/servicioTest",
success: function (responseData, textStatus, jqXHR) {
alert("Successfull: "+responseData);
},
error: function (responseData, textStatus, errorThrown) {
alert("Failed: "+responseData);
}
});
it worked fine for me. I hope that it can help you.
I faced the same issue recently and adding my solution which worked for me:
Following is what I did :
I created a class extending javax.ws.rs.core.Application and added a Cors Filter to it.
To the CORS filter, I added corsFilter.getAllowedOrigins().add("http://localhost:4200");.
Basically, you should add the URL which you want to allow Cross-Origin Resource Sharing. Ans you can also use "*" instead of any specific URL to allow any URL.
public class RestApplication
extends Application
{
private Set<Object> singletons = new HashSet<Object>();
public MessageApplication()
{
singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
CorsFilter corsFilter = new CorsFilter();
// To allow all origins for CORS add following, otherwise add only specific urls.
// corsFilter.getAllowedOrigins().add("*");
System.out.println("To only allow restrcited urls ");
corsFilter.getAllowedOrigins().add("http://localhost:4200");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
}
And here is my web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Restful Web Application</display-name>
<!-- Auto scan rest service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
There are some custom changes which you might not require or change like :
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
OR
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
OR
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
The most important code which I was missing when I was getting this issue was, I was not adding my class extending javax.ws.rs.Application i.e RestApplication to the init-param of <servlet-name>resteasy-servlet</servlet-name>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
And therefore my Filter was not able to execute and thus the application was not allowing CORS from the URL specified.
PS: I am using RestEasy version: 3.12.1.Final