Skip to content

Latest commit

 

History

History
118 lines (93 loc) · 4.33 KB

core-how-to-implement-a-custom-argument-resolver.md

File metadata and controls

118 lines (93 loc) · 4.33 KB

Core - How to implement a custom Argument Resolver

The framework uses an ArgumentResolverService to build the arguments for the method listener execution. The default core implementation, the DelegatingArgumentResolverService, uses ArgumentResolvers under the hood to resolve each type of argument.

You can define your own ArgumentResolverand include it in your ArgumentResolverService to extend what type of paramters you can consume.

new DelegatingArgumentResolverService(ImmutableSet.of(
     new MessageIdArgumentResolver(),
     ...
     new MyCustomArgumentResolver()
));

Example Use Case

There is a deeply nested payload in the SQS message, and it is desirable to only provide the field that is needed instead of passing the entire message body into the method. For example, using the sample SQS Message below, only the user's group is necessary and therefore a custom ArgumentResolver can be included to extract that field to any method parameter annotated with the @UserGroup annotation. example:

public void messageListener(@UserGroup final String userGroup) {
    // process mesage here
}

Example SQS Message

{
    "payload": {
        "user": {
            "group": "admin"
        }
    }
}

Steps

  1. Create a new annotation that indicates that this user group should be extracted.

    @Retention(value = RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface UserGroup {
    }
  2. Create a new implementation of the ArgumentResolver interface that will be able to resolve these arguments with those annotations.

    public class UserGroupArgumentResolver implements ArgumentResolver<String> {
    
        private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    
        @Override
        public boolean canResolveParameter(MethodParameter methodParameter) {
            // make sure only String parameters with the @UserGroup annotations are resolved using this
            return (
                methodParameter.getParameter().getType().isAssignableFrom(String.class) &&
                AnnotationUtils.findParameterAnnotation(methodParameter, UserGroup.class).isPresent()
            );
        }
    
        @Override
        public String resolveArgumentForParameter(QueueProperties queueProperties, MethodParameter methodParameter, Message message)
            throws ArgumentResolutionException {
            try {
                // You could build an actual POJO instead of using this JsonNode
                final JsonNode node = objectMapper.readTree(message.body());
                final JsonNode userGroupNode = node.at("/payload/user/group");
                if (userGroupNode.isMissingNode()) {
                    return null;
                } else {
                    return userGroupNode.textValue();
                }
            } catch (IOException e) {
                throw new ArgumentResolutionException("Error parsing payload", e);
            }
        }
    }
  3. Create a method that will use this argument, for example something like:

    public void messageListener(@UserGroup final String userGroup) {
        // Do something here
    }
  4. Build your ArgumentResolverService with this ArgumentResolver.

    new DelegatingArgumentResolverService(ImmutableSet.of(
         // other ArgumentResolvers here
         new UserGroupArgumentResolver()
    
    ));

Integrating with Spring

The Spring Starter provides an easier way to integrate argument resolvers, see spring-how-to-add-custom-argument-resolver.md.