Hi Thierry, I've just tried it on 2.0-RC1.
Here is a jUnit test case. SampleResource1 and SampleResource2 offer both plain text and HTML on GET, and for simplicity, only HTML on POST (but that's only determined by the method itself -- the problem is that it's not even called). SampleResource1 uses @Post. SampleResource2 uses @Post("html"). SampleResource3 disables content-type negotiation. The results are that posting a x-www-form-urlencoded entity to SampleResource1 and SampleResource2 doesn't work (the @Post-annotated methods are not called). Sending it to SampleResource3 works (but of course, content-type negotiation doesn't.) It just seems that the content negotiation feature affects both request and response types, and that the @Post annotation expect that type to be the same both ways. Is this by design, or is it a bug? Best wishes, Bruno. import org.junit.*; import org.restlet.*; import org.restlet.data.*; import org.restlet.representation.*; import org.restlet.resource.*; import org.restlet.routing.Router; import static org.junit.Assert.*; public class PostAnnotationTest { public final static String PLAINTEXT_TEST = "Hello World!"; public final static String HTMLTEXT_TEST = "<html><body><h1>Hello World!</h1></body></html>"; public final static String HTMLTEXT_FORM_TEST = "<html><body><h1>Hello %s!</h1></body></html>"; public final static String PARAM_NAME = "name"; public static abstract class AbstractSampleResource extends ServerResource { @Override protected void doInit() throws ResourceException { super.doInit(); setNegotiated(true); getVariants().add(new Variant(MediaType.TEXT_HTML)); getVariants().add(new Variant(MediaType.TEXT_PLAIN)); } @Get("html") public Representation toHtml() { return new StringRepresentation(HTMLTEXT_TEST, MediaType.TEXT_HTML); } @Get("txt") public Representation toText() { return new StringRepresentation(PLAINTEXT_TEST, MediaType.TEXT_PLAIN); } } public static class SampleResource1 extends AbstractSampleResource { @Post public Representation acceptForm(Representation entity) { if (entity .isCompatible(new Variant(MediaType.APPLICATION_WWW_FORM))) { Form postForm = new Form(entity); return new StringRepresentation( String.format(HTMLTEXT_FORM_TEST, postForm .getFirstValue(PARAM_NAME)), MediaType.TEXT_HTML); } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return null; } } } public static class SampleResource2 extends AbstractSampleResource { @Post("html") public Representation acceptForm(Representation entity) { if (entity .isCompatible(new Variant(MediaType.APPLICATION_WWW_FORM))) { Form postForm = new Form(entity); return new StringRepresentation( String.format(HTMLTEXT_FORM_TEST, postForm .getFirstValue(PARAM_NAME)), MediaType.TEXT_HTML); } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); return null; } } } public static class SampleResource3 extends SampleResource2 { @Override protected void doInit() throws ResourceException { super.doInit(); setNegotiated(false); } } public static class SampleApplication extends Application { @Override public synchronized Restlet createInboundRoot() { Router router = new Router(getContext()); router.attach("sr1", SampleResource1.class); router.attach("sr2", SampleResource2.class); router.attach("sr3", SampleResource3.class); return router; } } int portnumber = 50000; Component component; @Before public void setUp() throws Exception { portnumber++; component = new Component(); component.getServers().add(Protocol.HTTP, portnumber); component.getDefaultHost().attach("/", new SampleApplication()); component.start(); } @After public void tearDown() throws Exception { if (component != null) { component.stop(); } } @Test public void testSr1GetPlainText() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr1", portnumber)); testResource.get(MediaType.TEXT_PLAIN); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_PLAIN, testResource.getResponse() .getEntity().getMediaType()); assertEquals(PLAINTEXT_TEST, testResource.getResponse().getEntity() .getText()); } @Test public void testSr1GetHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr1", portnumber)); testResource.get(MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, testResource.getResponse().getEntity() .getText()); } @Test public void testSr1PostFormHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr1", portnumber)); Form postForm = new Form(); postForm.add(PARAM_NAME, "World"); testResource.post(postForm.getWebRepresentation(), MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, String.format(HTMLTEXT_FORM_TEST, postForm .getFirstValue(PARAM_NAME))); } @Test public void testSr2GetPlainText() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr2", portnumber)); testResource.get(MediaType.TEXT_PLAIN); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_PLAIN, testResource.getResponse() .getEntity().getMediaType()); assertEquals(PLAINTEXT_TEST, testResource.getResponse().getEntity() .getText()); } @Test public void testSr2GetHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr2", portnumber)); testResource.get(MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, testResource.getResponse().getEntity() .getText()); } @Test public void testSr2PostFormHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr2", portnumber)); Form postForm = new Form(); postForm.add(PARAM_NAME, "World"); testResource.post(postForm.getWebRepresentation(), MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, String.format(HTMLTEXT_FORM_TEST, postForm .getFirstValue(PARAM_NAME))); } @Test public void testSr3GetHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr3", portnumber)); testResource.get(MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, testResource.getResponse().getEntity() .getText()); } @Test public void testSr3PostFormHtml() throws Exception { ClientResource testResource = new ClientResource(String.format( "http://localhost:%d/sr3", portnumber)); Form postForm = new Form(); postForm.add(PARAM_NAME, "World"); testResource.post(postForm.getWebRepresentation(), MediaType.TEXT_HTML); assertTrue(testResource.getStatus().isSuccess()); assertEquals(MediaType.TEXT_HTML, testResource.getResponse() .getEntity().getMediaType()); assertEquals(HTMLTEXT_TEST, String.format(HTMLTEXT_FORM_TEST, postForm .getFirstValue(PARAM_NAME))); } } Thierry Boileau wrote: > Hello Bruno, > > what release of Restlet are you using? I think the 405 status has been > fixed recently. > > Best regards, > Thierry Boileau > >> Hi, >> >> >> Firstly, I'd like to write a ServerResource that uses @Get("xml") and >> @Get("html") for content negotiation on GET but not on POST (where it >> would return a different content-type depending on what the method does, >> or do the negotiation internally). >> Secondly, I'd like to be able to post some >> "application/x-www-form-urlencoded" content and get another type in return. >> >> >> public class MyResource extends >> ServerResource { >> @Override >> protected void doInit() throws ResourceException { >> super.doInit(); >> setNegotiated(true); >> getVariants().add(new Variant(MediaType.TEXT_HTML)); >> getVariants().add(new Variant(MediaType.APPLICATION_XHTML)); >> getVariants().add(new Variant(MediaType.APPLICATION_RDF_XML)); >> } >> >> @Get("html") >> public Representation toHtml() throws ResourceException { >> ... >> } >> >> @Get("xml") >> public Representation toXml() throws ResourceException { >> ... >> } >> >> @Post >> public Representation accept(Representation entity) throws >> ResourceException { >> ... >> } >> } >> >> >> At the moment, if I turn off the content-type negotiation >> (setNegotiated(false)), then 'accept' is being called up receiving a >> POST request. If content-negotiation is on (setNegotiated(true)), I get >> a 405 (method not allowed) error. >> It looks like this is due to the logic in doNegotiatedHandle(), which >> I'd rather not override. >> >> >> I'm not entirely sure it's because of the content-type negotiation on >> the returned type, but it might be due to the input type too. (Hence the >> second part of this problem.) >> >> I've tried this @Post("html"), @Post("xml") and @Post("html|xml"), but >> they're never called anyway, so it doesn't seem to have much to do with >> the negotiated return type (the browser accepts "*/*" by the way). >> >> What's posted is of type "application/x-www-form-urlencoded". It looks >> like the @Post annotation make the negotiation on the input type too. >> If I tweak client to send the same content as "text/html", the >> @Post("html") is called. This seems a bit wrong (posting >> x-www-form-urlencoded forms and getting HTML in return seems quite >> common, and that doesn't seem feasible if content-type negotiation is on). >> Did I miss something? Any workarounds? >> >> >> Best wishes, >> >> Bruno. >> >> ------------------------------------------------------ >> http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2460162 >> >> ------------------------------------------------------ http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2460607