I found an acceptable work-around:
I replaced the @Path("") on the concrete classes with @Path("/account"),
@Path("/roles"), etc. (and changed/removed the paths on the interface
methods accordingly).
Although that means part of my REST "interface" is defined on the
implementation classes, it's limited to part of the relative uri path.
I now have a single Application subclass that switches between the dummy
and real implementation:
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<Class<?>>(1);
if (Boolean.getBoolean("DUMMY_API")) {
set.add(DummyAccountService.class);
...
set.add(DummyRoleService.class);
} else {
set.add(AccountService.class);
...
set.add(RoleService.class);
}
return set;
}
And that's working fine, so I'm a happy camper J
Regards,
Dies Koper
From: Koper, Dies [mailto:diesk_at_fast.au.fujitsu.com]
Sent: Saturday, September 14, 2013 12:12 PM
To: users_at_jersey.java.net
Subject: [Jersey] Re: separation of interfaces and implementation class:
works in Jersey, not in GlassFish
1. It looks to me like you're adding your interface and your
implementation
both to the Application classes. That doesn't seem right to me.
Thanks for the reply. At first I only had the concrete classes so I
started experimenting.
I've taken the interfaces out again. Still get the same error.
I learned a bit more after more experimenting:
I emptied my web.xml and only specified one concrete class in my
Application implementation.
That resource then works.
As soon as I add a second, I get the error again.
So it seems GF's jersey doesn't like having multiple resource classes
with the same path specified on the class, while the latest Jersey
doesn't seem to mind?
Or is there still something I'm doing wrong?
Cheers,
Dies Koper
On Fri, Sep 13, 2013 at 7:42 AM, Koper, Dies <diesk@...>wrote:
I'm developing a REST API using JAX-RS 1.1 (it has to run on GF
3.1.2.2).
I want to separate the interfaces and implementation because there are
different teams doing the real implementation and (for testing) a dummy
implementation:
I don't want the implementers to have any control over the interfaces.
Currently I have the following, which runs fine in Jersey 2.1, but gives
a "Conflicting URI templates." error on GF:
[#|2013-09-13T15:02:46.353+0900|SEVERE|glassfish3.1.2|com.sun.jersey.spi
.inject.Errors|_ThreadID=95;_ThreadName=Thread-2;|The following errors
and warnings have been detected with resource and/or provider classes:
SEVERE: Conflicting URI templates. The URI template / for root
resource class my.api.impl.AccountService and the URI template /
transform to the same regular expression (/.*)?
Source code:
package my.api;
public interface AccountResource {
@GET
@Path("/account")
@Produces(MediaType.APPLICATION_JSON)
Account getAccount();
}
and
package my.api.impl;
@Path("")
public class AccountService implements AccountResource {
@Override
public Account getAccount() {
return foo;
}
}
The suggestion of @Path("") on the concrete class came from on old post
on this list.
(maybe relevant, but I have multiple interfaces and implementations like
this, e.g. RoleResource under "/roles" with a RoleService with @Path("")
as above.)
The deployment methods to Jersey and GF are different, I don't know if
that's relevant too.
For Jersey, I host the endpoint using Jersey specific classes:
final ResourceConfig rc = new ResourceConfig()
.packages("my.api");
return
GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI),
rc);
With GlassFish, I added a web.xml and application implementation class:
<web-app xmlns="
http://java.sun.com/xml/ns/javaee"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>my.api.RestApplication</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>my.api.RestApplication</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
With:
@ApplicationPath("api/*")
public class RestApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<Class<?>>(1);
set.add(AccountResource.class);
set.add(RoleResource.class);
set.add(AccountService.class);
set.add(RoleService.class);
return set;
}
}
What am I doing wrong?
Cheers,
Dies Koper