From 426cfe4290b8cd57bc43212d47c4cb477dc2485a Mon Sep 17 00:00:00 2001 From: Norman Niati Date: Mon, 18 May 2026 16:55:57 +0200 Subject: [PATCH] fix(plugin-id/backend): expose @POST create() on GroupResource and CompanyResource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The parent AbstractContainerResource declares @POST create(V container) at line 149, but JAX-RS doesn't pick up the annotation on the concrete bean because of type erasure on the generic parameter. Result: POST /group and POST /company returned 405 Method Not Allowed, blocking container creation from the UI. Re-declare create() with the concrete type and the @POST annotation in GroupResource and CompanyResource, delegating to super.create() — same pattern as UserOrgResource.java:360 which has always worked. Also override @Produces with text/plain on these two methods: the return value is a raw identifier string, not a JSON document. With the class-level JSON default the serializer emits an unquoted scalar that clients cannot parse (e.g. response.json() throws SyntaxError). text/plain matches the actual payload and lets clients read it via response.text(). PUT/update on containers is out of scope (not declared on the abstract parent either, would require a new implementation). To be addressed in a separate PR if needed. --- .../plugin/id/resource/CompanyResource.java | 19 +++++++++++++++++++ .../app/plugin/id/resource/GroupResource.java | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/main/java/org/ligoj/app/plugin/id/resource/CompanyResource.java b/src/main/java/org/ligoj/app/plugin/id/resource/CompanyResource.java index 17094ae..885f3be 100644 --- a/src/main/java/org/ligoj/app/plugin/id/resource/CompanyResource.java +++ b/src/main/java/org/ligoj/app/plugin/id/resource/CompanyResource.java @@ -5,6 +5,7 @@ import jakarta.transaction.Transactional; import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; @@ -137,6 +138,24 @@ public TableItem findAll(@Context final UriInfo uriInfo) { }); } + /** + * Create the given company. Concrete re-declaration of the inherited + * {@code @POST create(V)} from {@link AbstractContainerResource} so JAX-RS + * registers the route on the concrete bean — the parent annotation isn't + * picked up because of type erasure on the generic parameter V. + * + *

Produces {@code text/plain} (not the class-level JSON default): the + * returned identifier is a raw string, not a JSON document, so clients can + * read it via {@code response.text()} instead of failing to parse an + * unquoted scalar as JSON. + */ + @POST + @Produces(MediaType.TEXT_PLAIN) + @Override + public String create(final ContainerEditionVo container) { + return super.create(container); + } + @Override protected void checkForDeletion(final ContainerOrg container) { super.checkForDeletion(container); diff --git a/src/main/java/org/ligoj/app/plugin/id/resource/GroupResource.java b/src/main/java/org/ligoj/app/plugin/id/resource/GroupResource.java index 188f9ad..c324181 100644 --- a/src/main/java/org/ligoj/app/plugin/id/resource/GroupResource.java +++ b/src/main/java/org/ligoj/app/plugin/id/resource/GroupResource.java @@ -113,6 +113,24 @@ public boolean exists(@PathParam(GROUP_ATTRIBUTE) final String group) { return findById(group) != null; } + /** + * Create the given group. Concrete re-declaration of the inherited + * {@code @POST create(V)} from {@link AbstractContainerResource} so JAX-RS + * registers the route on the concrete bean — the parent annotation isn't + * picked up because of type erasure on the generic parameter V. + * + *

Produces {@code text/plain} (not the class-level JSON default): the + * returned identifier is a raw string, not a JSON document, so clients can + * read it via {@code response.text()} instead of failing to parse an + * unquoted scalar as JSON. + */ + @POST + @Produces(MediaType.TEXT_PLAIN) + @Override + public String create(final GroupEditionVo container) { + return super.create(container); + } + @Override protected String toDn(final GroupEditionVo container, final ContainerScope scope) { var parentDn = scope.getDn();