Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resteasy Reactive: Ignore JAX-RS Resource method field thanks to custom logic #39979

Closed
poldinik opened this issue Apr 10, 2024 · 4 comments
Closed
Labels
area/rest kind/enhancement New feature or request

Comments

@poldinik
Copy link
Contributor

Description

In order to provide an augmentation of JAX-RS API, it would be nice if we could ignore a field as it was an un-annotated fields: so “field” variable result would be the result of evaluation of custom predicate/service defined by user, here the snippet I'm referring

//un-annotated field
//just ignore it
if (field) {
    return builder;
}

Why this? This is my use case:

I’ll try to define new kind of API built on top of JAX-RS. These API allow to inject inside the signature of JAX-RS resource method, some entities provided by some logic under the hood before actual invocation of method.

Why not a @Context as alternative to define custom field? Because these API are part of set of new API that have a specific semantic with respect JAX-RS, so it is a high level specification that don’t needs JAX-RS.

To go in depth of my domain use case, the new framework I’m designing provides APIs to design chatbot. Every chatbot needs to define a set of intents. Every intent matches a specific REST routing, but needs injection of some chatbot context entities.

These APIs are an orthogonal specification with respect JAX-RS, but the implementation chosen is using JAX-RS baseline to inherits features that we need to guarantees the expected behavior, so @Context would be not acceptable as alternative.

Chatbot is new kind of interface that combines some features inherited by REST API definition (like using same http protocols) and some new add-on concepts.

This feature allows to enrich JAX-RS layer and will fix this current problem


    @Intent
    @Path("/reservations")
    @Produces(MediaType.APPLICATION_JSON)
    @POST
    public Response reserve(@Referred ReservationRequest request, @Prompt String prompt){
        return Response.ok().build();
    }

This kind of method throws "Resource method " + info + " can only have a single body parameter" exception because "field" is constant to false and the builder set

builder.setName(sourceName);
builder.setType(ParameterType.BODY);

So the type it will be not null and throws exception because there is more then one field.

Implementation ideas

To implement this feature

extractParameterInfo(currentClassInfo, actualEndpointInfo, currentMethodInfo,
                            existingConverters, additionalReaders,
                            anns, paramType, errorLocation, false, hasRuntimeConverters, pathParameters,
                            currentMethodInfo.parameterName(i),
                            consumes,
                            methodContext);

"field" param is constant to false, so I would like to replace it with a function result, adding a predicate like this
private Predicate<Map<DotName, AnnotationInstance>> skipMethodParameter = null;. I see that is done only for reactive rest client purpose with respect NotBody annotation. This predicate will be init during build phase of deployment processor with a custom bean defined by user. Then I could use a custom definition to decide how to skip a field as it was a un-unnotated field

@poldinik poldinik added the kind/enhancement New feature or request label Apr 10, 2024
Copy link

quarkus-bot bot commented Apr 10, 2024

/cc @FroMage (resteasy-reactive), @geoand (resteasy-reactive), @stuartwdouglas (resteasy-reactive)

@geoand
Copy link
Contributor

geoand commented Apr 10, 2024

I'd like to see a draft PR of what you have in mind

poldinik added a commit to poldinik/quarkus that referenced this issue Apr 11, 2024
… by user

[ResteasyReactiveProcessor inits skipMethodParameter if there is a predicate annotated with @RestEasyParamsFilter by user. This allows to ignore params chosen by user logic marking them as SKIPPED in order to use different annotated params with respect JAXRS api]
poldinik added a commit to poldinik/quarkus that referenced this issue Apr 11, 2024
… by user

[ResteasyReactiveProcessor inits skipMethodParameter if there is a predicate annotated with @RestEasyParamsFilter by user. This allows to ignore params chosen by user logic marking them as SKIPPED in order to use different annotated params with respect JAXRS api]
poldinik added a commit to poldinik/quarkus that referenced this issue Apr 11, 2024
… by user

[ResteasyReactiveProcessor inits skipMethodParameter if there is a predicate annotated with @RestEasyParamsFilter by user. This allows to ignore params chosen by user logic marking them as SKIPPED in order to use different annotated params with respect JAXRS api]
@poldinik
Copy link
Contributor Author

poldinik commented Apr 11, 2024

I'd like to see a draft PR of what you have in mind

#40031

The part of init of predicate could be implemented better, I guess. Any advice could help.

BTW, it should be a draft for proposal. In particular, for cases like

@RestEasyParamsFilter
public class RestEasyFilterImpl implements Predicate<Map<DotName, AnnotationInstance>> {
    @Override
    public boolean test(Map<DotName, AnnotationInstance> dotNameAnnotationInstanceMap) {
        DotName PROMPT = DotName.createSimple(Prompt.class.getName());
        return dotNameAnnotationInstanceMap.containsKey(PROMPT);
    }
}

A rest easy method like this could be indexed skipping (in this case) param annotated with @prompt, but using benefits of jax rs api. The skipped param will be in generale handled by other logic (interceptor and other stuff) to provide implementation of framework

@Path("/greetings/send")
@Produces(MediaType.APPLICATION_JSON)
@POST
public Response send(MyRequest request, @Prompt String prompt){
    return Response.ok(Map.of("request", request)).build();
}

Note that these kind of skips should be used only inside an extension deployment definition, because is a logic that is decided by the framework that user is importing, on top of jaxrs.

If you compare the implementation inside PR, you see that I have reused your SKIPPED logic instead edit extractParameterInfo logic as I said before; the result is the same as expected

@poldinik
Copy link
Contributor Author

Feature introduced with #40031

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/rest kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants