Trying a simple REST implementation on OSGi Equinox + Jetty - simple REST deploy using web.xml
Below are the details of my implementation:
Resource file:
#Path("jsonstatus")
public class JsonResource {
private static Logger logger = LoggerFactory.getLogger(JsonResource.class);
#GET
#Produces("application/json")
public String listConferences() {
logger.info("Returning the status");
return "{\"status\": \"success\"}";
}
}
Application Implementation:
public class JerseyApplication extends Application {
private static Logger logger = LoggerFactory.getLogger(JerseyApplication.class.getName());
#Override
public Set<Class<?>> getClasses() {
logger.info("--Returning all the claess-");
Set<Class<?>> result = new HashSet<Class<?>>();
result.add(JsonResource.class);
result.add(StatusResource.class);
return result;
}
}
web.xml:
<servlet>
<servlet-name>SimpleREST</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.learnings.osgi.rest.jetty.activator.JerseyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SimpleREST</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
All the OSGi core, console and jetty jars are added: When I start the Equinox, i get the below error. I dont have the activator mapped to bundle when i deployed using web.xml
But with activator and web.xml removed, REST API works, No error during equinox startup.
Simple Activator:
#Override
public void start(BundleContext context) throws Exception {
logger.info("Starting the bundle");
ServletContextHandler ch = new ServletContextHandler();
ch.setContextPath("/");
ServletHolder holder = new ServletHolder(new ServletContainer());
holder.setInitParameter("javax.ws.rs.Application", JerseyApplication.class.getName());
ch.addServlet(holder, "/*");
context.registerService(ContextHandler.class.getName(), ch, null);
}
When searched in the internet, i saw, need to configure JNDI, This is very basic simple REST which does not require a database. So got confused why we need JNDI. Some article discussed about initialization of the java.naming.factory.initial. But those are given for jboss. Not sure how to configure the initial context for jetty.All the combinations i tried are in the github code.
If you could help to get the initial context configured in the OSGi-jetty would really a great help. I am looking for a deployment with web.xml way of servlet creation on OSGi with jetty
Below repository contains the code which I tried:
https://github.com/pkolanda/my-learning-osgi-simple-rest-with-jetty
to run the code, mvn clean install and run the run.sh shell script under the target/my-learning-osgi-simple-rest-with-jetty-0.1 folder.
Meanwhile i am looking into this post
Log:
11:14:33.951 [Start Level: Equinox Container: 6ee1939d-123f-4def-860f-dfc2e21bdfc4] WARN o.eclipse.jetty.webapp.WebAppContext - Failed startup of context o.e.j.w.WebAppContext#7c19344a{/my-learning-osgi-simple-rest-with-jetty-1.0-SNAPSHOT,file:///tmp/jetty-0.0.0.0-8081-my-learning-osgi-simple-rest-with-jetty-1.0-SNAPSHOT.jar-_my-learning-osgi-simple-rest-with-jetty-1.0-SNAPSHOT-any-9046322855444487913.dir/webapp/,UNAVAILABLE}{file:/home/prakash/mygit/my-learning-osgi-simple-rest-with-jetty/target/my-learning-osgi-simple-rest-with-jetty-0.1/plugins/my-learning-osgi-simple-rest-with-jetty-1.0-SNAPSHOT.jar}
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:350)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at org.eclipse.jetty.plus.webapp.EnvConfiguration.createEnvContext(EnvConfiguration.java:258)
at org.eclipse.jetty.plus.webapp.EnvConfiguration.preConfigure(EnvConfiguration.java:67)
at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:506)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:544)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:46)
at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:192)
at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:505)
at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:151)
at org.eclipse.jetty.osgi.boot.BundleWebAppProvider.bundleAdded(BundleWebAppProvider.java:214)
at org.eclipse.jetty.osgi.boot.BundleWebAppProvider$WebAppTracker.addingBundle(BundleWebAppProvider.java:80)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:475)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:450)
at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:911)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:233)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:233)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:140)
at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:132)
at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:194)
at org.eclipse.osgi.container.Module.publishEvent(Module.java:483)
at org.eclipse.osgi.container.Module.start(Module.java:474)
at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1783)
at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1763)
at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1725)
at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1656)
at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:233)
at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:343)
____________________________
Welcome to Apache Felix Gogo
g!
Related
I made a little SOAP web service using Spring Boot, with the following files (only relevant files are shown):
WebServiceConfig.Java
#EnableWs
#Configuration
public class WebServiceConfig {
#Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(context);
messageDispatcherServlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<MessageDispatcherServlet>(messageDispatcherServlet, "/ws/*");
}
#Bean(name = "consultas")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema consultasSchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setPortTypeName("ConsultasPort");
definition.setTargetNamespace("http:/site.com/consultas");
definition.setLocationUri("/ws");
definition.setSchema(consultasSchema);
return definition;
}
#Bean
public XsdSchema consultasSchema() {
return new SimpleXsdSchema(new ClassPathResource("consultas.xsd"));
}
}
application.properties
server.port=9090
Main.Java
#SpringBootApplication
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
System.setProperty("org.jboss.logging.provider", "slf4j2");
SpringApplication.run(Main.class, args);
}
}
Problem description:
When I run Main.Java from Eclipse, a Tomcat instance is deployed. Visiting the address http://localhost:9090/ws/consultas.wsdl. shows the WSDL description file, and SOAPUI is able to consume the web services without a problem.
The problem starts when I pack the .war and deploy it on wildfly-23.0.2.Final. The context root is always set to /soap-web-service-0.0.1-SNAPSHOT.
Edit 2021 05 17
I was able to change the WildFly endpoint by creating a jboss-web.xml file in the folder src\main\webapp\WEB-INF, with the following contents:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.jboss.com/xml/ns/javaee
http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<context-root>/ws/*</context-root>
</jboss-web>
Steps I tried
I tried setting
to:
/
/ws/*
But I'm still unable to reach the endpoint
Any input will be greatly appreciated.
UPDATE Months later I just found the answer by accident, answered by user #pascal-thivent
...you access the WSDL at:
http://localhost:8080//services/hello?wsdl
A B C D
A is the host and port of the servlet container.
B is the name of the war file.
C comes from the url-pattern element in the web.xml file.
D comes from the ending stem of the url-pattern attribute in the sun-jaxws.xml file
I am trying to implement sort of conditional import bean context files within current spring application. To make this work, I use similar solution in SO to extend the ApplicationContextInitializer<ConfigurableApplicationContext>
package com.mydepartment.app.util;
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment env = applicationContext.getEnvironment();
// load from web.xml context-param
String propertyFileClassPath = env.getProperty("propertyFileClassPath");
try {
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(new ResourcePropertySource(new ClassPathResource(propertyFileClassPath)));
} catch (IOException ioException) {
LOG.info(ioException.getMessage());
LOG.error( "Loading resource failed..", ioException);
}
}
}
And this is want I add into web.xml to make current application to be able to load the properties file which contains the properties which defines the condition
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.mydepartment.app.util.MyApplicationContextInitializer</param-value>
</context-param>
<context-param>
<param-name>propertyFileClassPath</param-name>
<param-value>classpath*:application-env.properties</param-value>
</context-param>
.....
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
the application-env.properties resides in
%war_file_name%\WEB-INF\classes\application-env.properties
but above configuration/coding returns following error in both WebLogic and Websphere, which makes me really miserable for the fix:
2015-10-15 13:23:12,625 -- INFO -- com.mydepartment.app.util.MyApplicationContextInitializer -- class path resource [classpath*:application-env.properties] cannot be opened because it does not exist
2015-10-15 13:23:12,626 -- ERROR -- com.mydepartment.app.util.MyApplicationContextInitializer -- Loading resource failed..
java.io.FileNotFoundException: class path resource [classpath*:application-env.properties] cannot be opened because it does not exist
I tried several pattern to establish the classpath but all failed, such as:
classpath*:application-env.properties
file:/WEB-INF/classes/application-env.properties
/WEB-INF/classes/application-env.properties
../classes/application-env.properties
Potentially I want the application to load the init properties from properties file inside the application, instead of system properties or server properties. But I don't see the necessity to add the properties file into the server's classpath.
I don't see any reason that the application server blocks access to this internal properties file.
When we use ClassPathResource, we directly specify the resource path. Try the following:
ClassPathResource cr = new ClassPathResource("application-env.properties");
I am using apache commons + log4j for my web app.
normally log4j needs a configuration file inside the classpath; but I need to delegate the logging configuration to an external file (I need to deploy a .war in an environment, but the log configurations (max size, position, etc) it's up to a second team.
I have a commons-logging.properties in my classpath
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
# log4j.configuration=/absolute/path/where/external/logs/are/log4j.properties
unfortunately, the commented line doesn't work.
Is there a way to set up log4j with an external configuration file?
You can set it as a system property log4j.configuration property .. for example in J2SE app
java -Dlog4j.configuration=file:/path/to/log4j.properties myApp
Note, that property value must be a URL.
For more read section 'Default Initialization Procedure' in Log4j manual.
It's also possible letting a ServletContextListener set the System properties:
import java.util.Enumeration;
import javax.servlet.*;
public class SystemPropertiesHelper implements
javax.servlet.ServletContextListener {
private ServletContext context = null;
public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
Enumeration<String> params = context.getInitParameterNames();
while (params.hasMoreElements()) {
String param = (String) params.nextElement();
String value =
context.getInitParameter(param);
if (param.startsWith("customPrefix.")) {
System.setProperty(param, value);
}
}
}
public void contextDestroyed(ServletContextEvent event) {
}
}
And then put this into your web.xml (should be possible for context.xml too)
<context-param>
<param-name>customPrefix.property</param-name>
<param-value>value</param-value>
<param-type>java.lang.String</param-type>
</context-param>
<listener>
<listener-class>servletUtils.SystemPropertiesHelper</listener-class>
</listener>
I got this from this listener code from answer .
I hope this could help you!
You can use a jvm parameter indicating the configuration file path:
-Dlog4j.configuration=absolute path
example with an absolute path:
java -Dlog4j.configuration="file:/dir1/log4j.properties"
Set the system property log4j.configuration=/abslute/or/relative/path_to_file_name
commons logging only needs to know what logging implementation it's using, the logging implementation it self is configured in whatever way it is always configured in.
This is documented in the log4j manual.
If you are using the Spring Framework, you can use the org.springframework.web.util.Log4jConfigListener.
You only need to specify the parameter log4jConfigLocation with the file location (using the URL for File). e.g.:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>file:/absolute/path/where/external/logs/are/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>1000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
You can specify the log4jRefreshInterval, the interval between config file refresh checks, in milliseconds.
See more in the javadoc of org.springframework.web.util.Log4jWebConfigurer.
I am trying to configure my Jersey application using my own Application implementation or an extended ResourceConfig or PackageResourceConfig. So, my first attempt consists in porting an exisiting web.xml (actually I'm using web-fragment.xml because of library nature of my development) configuration to MyApplication implementation.
This is the working web-fragment.xml before porting
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>my.pkg.resources;org.codehaus.jackson.jaxrs</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>my.pkg.Filter1;my.pkg.Filter2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Below, modified web-fragment.xml
<servlet>
<servlet-name>my.pkg.MyApplication</servlet-name> <!-- implementation follows -->
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>my.pkg.MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
and MyApplication class
// [...]
public class MyApplication extends PackagesResourceConfig {
private static final Logger logger = Logger.getLogger(MyApplication.class);
#Context
ServletConfig config
public MyApplication() {
super("my.pkg.resources;org.codehaus.jackson.jaxrs");
super.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
// filters not set
}
#PostConstruct
public void readInitParams() {
// read init params from ServletConfig
// config.getInitParameterNames();
// ...
}
}
Anytime I use the second version, I receive the following
mag 27, 2013 12:08:03 PM com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
aero.aice.jerico.rs;org.codehaus.jackson.jaxrs;
mag 27, 2013 12:08:03 PM com.sun.jersey.server.impl.application.DeferredResourceConfig$ApplicationHolder <init>
INFO: Instantiated the Application class my.package.MyApplication. The following root resource and provider classes are registered: [class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver, class org.codehaus.jackson.jaxrs.JsonParseExceptionMapper, class org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider, class org.codehaus.jackson.jaxrs.JsonMappingExceptionMapper, class aero.aice.jerico.rs.service.OperationService, class aero.aice.jerico.rs.service.CrudService, class org.codehaus.jackson.jaxrs.JacksonJsonProvider]
mag 27, 2013 12:08:03 PM com.sun.jersey.core.spi.component.ProviderFactory __getComponentProvider
SEVERE: The provider class, class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver, could not be instantiated. Processing will continue but the class will not be utilized
java.lang.InstantiationException: com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver
mag 27, 2013 12:08:04 PM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: The class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver is a not a public class and cannot be instantiated.
SEVERE: The inner class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver is not a static inner class and cannot be instantiated.
As you can see, com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver is the first registered class but that is not instantiable because it is not public and not a static inner class.
I have found very little documentation about this procedure and in particular, how to set features and properties during initialization.
I am using the last available version of Jersey (1.17.1) but have tested with 1.9 too.
Is it also possible to set application path, programatically? I have seen #ApplicationPath in documentation but it is not useful for my purpose because i need to set it at runtime.
I know these are more questions but I think they all lead to the same root.
Can anybody point me to the right direction?
Make sure you have no jersey libs on path which is scanned for resource classes.
Base URI you can set only during deployment. Using war name or #ApplicationPath. You can override it using servlet-mapping element in the web.xml.
I had go through similar problem:
SEVERE: The class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver is a not a public class and cannot be instantiated.
SEVERE: The inner class com.sun.jersey.server.impl.application.WebApplicationImpl$1WadlContextResolver is not a static inner class and cannot be instantiated.
This error freaked me out... Basically I am using GlassFish 3.x. It has already one jersey.core.jar included. But I needed a jersey-server lib. My libs was:
jersey.core.jar -> MANIFEST.MF -> 1.11.1
jersey-server-1.17.1
My problem was I mixed JARs from different Jersey versions. When I go for jersey-server-1.11.1 I don't see this error anymore.
RESTEasy 2.0.1GA
Java 1.6
Spring 3.0.3
I have tried everything I can, and cannot make head or tail of what's going on. I have a Spring MVC application, however I'd like to have some RESTEasy endpoints available outside the Spring MVC app, but in the same container, ultimately being able to wire in the same beans.
As a first step, I'm simply trying to stand-up RESTEasy inside the container, serving requests from a Spring-configured bean. I have tried the boilerplate from the instructions and have also tried manual setup, to no avail.
Bean
#Resource
#Path("/")
public class NeighborComparison {
private String foo;
#GET #Path(value="customer") #Produces("text/plain")
public String getNeighborComparison() {
return "foo";
}
}
web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<!-- NOT configuring SpringContextLoaderListener because I declare my own, so if I do, everything
blows up, plus all it actually does is sanity check configuration -->
<listener>
<listener-class>com.example.MyCustomContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<bean id="resteasy.providerFactory" class="org.jboss.resteasy.spi.ResteasyProviderFactory"
factory-method="getInstance">
</bean>
<bean id="resteasy.dispatcher" class="org.jboss.resteasy.core.SynchronousDispatcher">
<constructor-arg ref="resteasy.providerFactory"/>
</bean>
<bean id="resteasy.spring.bean.processor" class="org.jboss.resteasy.plugins.spring.SpringBeanProcessor">
<description>
Add Resources and #Providers to the appropriate places
in Resteasy's infrastructure
</description>
<constructor-arg ref="resteasy.dispatcher"/>
</bean>
<bean id="neighborComparison" class="opower.api.customer.neighbor_comparison.NeighborComparison">
</bean>
According to the documentation, all I have to do is “manually register the RESTeasy BeanFactoryPostProcessor by allocating an instance of org.jboss.resteasy.plugins.spring.SpringBeanProcessor”. I believe this spring configuration does that.
Jetty starts and the app context spins up with no issues. Application works normally, however when I
> curl -H"Accept: text/plain" localhost:8080/ei/api/customer
("ei" is the application context). The log shows (this and only this):
2011-03-29 16:44:24,153 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] PathInfo: /customer
2011-03-29 16:44:24,156 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] Failed executing GET /customer
org.jboss.resteasy.spi.NotFoundException: Could not find resource for relative : /customer of full path: http://localhost:8080/ei/api/customer
Even if I could convince RESTEasy to show me the mappings, it seems that it's just not discovering my bean.
If I map it explicitly via the resteasy.resources context param, it works, though obviously doesn't have access to auto-wired Spring beans.
Anything else I can try? I have debug log on the entire RESTEasy codebase and I don't get any messages. I've also confirmed that Spring is, in fact, creating my bean, so it's just that RESTEasy isn't finding it.
Your resource class needs to be annotated with #Path annotation for RESTeasy to pick up on it during bootstrap:
#Path("/customer")
#Resource
public class NeighborComparison {
#GET #Path("/{customerId}") #Produces("text/plain")
public String getNeighborComparison(#PathParam("customerId") long customerId) {
return "foo";
}
}
Note the #Path("/{customerId}} annotation without which your #PathParam parameter would not have been mapped correctly, resulting in a pretty detailed exception (and an accompanying 500 response on the client side). Assuming the service is picked up by RESTeasy of course.
In addition if you don't use RESTeasy's SpringContextLoader, you have to make sure your SpringBeanProcessor instance is registered with the ApplicationContext. RESTeasy delegates to it by registering an ApplicationListener in SpringContextLoader:
ApplicationListener listener = new ApplicationListener() {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ContextRefreshedEvent cre = (ContextRefreshedEvent) event;
ConfigurableListableBeanFactory autowireCapableBeanFactory = (ConfigurableListableBeanFactory) cre
.getApplicationContext().getAutowireCapableBeanFactory();
new SpringBeanProcessor(dispatcher, registry, providerFactory)
.postProcessBeanFactory(autowireCapableBeanFactory);
}
}
};
configurableWebApplicationContext.addApplicationListener(listener);
If using a custom context loader and not the RESTEasy-provided one, this code has to appear somewhere in your context loader so that everything gets wired up. A bit convoluted, yeah. It is SpringBeanProcessor that goes through all Spring beans and registers with RESTeasy those that have a #Path annotation somewhere in their hierarchy (type and their corresponding interfaces).