在 quarkus 过滤器中添加请求查询参数

Add request query params in quarkus filter

我有一个 url 喜欢 http://localhost:8080?scope=openid%20profile

我要转给http://localhost:8080?scope=openid&scope=profile 以便以下端点可以接受它。

// Scope.java
public enum Scope {
  OPENID,
  PROFILE;
  public static Scope fromString(String value) {
    return valueOf(value.toUpperCase());
  }
}

// AuthorizationEndpoint.java
  @GET
  @Path("authorize")
  public Response authorize(@Valid @NotEmpty @QueryParam("scope") Set<Scope> scope) {
    ...
  }

我尝试添加如下过滤器,但请求参数映射 不可修改 !

// Split.java
public @interface Split {
    String value();
}

// AuthorizationEndpoint.java
  @GET
  @Path("authorize")
  // add @Split(" ")
  public Response authorize(@Valid @NotEmpty @QueryParam("scope") @Split(" ") Set<Scope> scope)    
  {
    ...
  }

// SplitFilter.java
@Provider
class SplitFilter implements ContainerRequestFilter {
    
    private final ResourceInfo resourceInfo;

    SplitFilter(ResourceInfo resourceInfo) {
        this.resourceInfo = resourceInfo;
    }
    
    @Override
    public void filter(ContainerRequestContext requestContext) {
        for (var parameter: resourceInfo.getResourceMethod().getParameters()) {
            var queryParam = parameter.getAnnotation(QueryParam.class);
            if (queryParam == null) continue;
            var split = parameter.getAnnotation(Split.class);
            if (split == null) continue;
            var queryName = queryParam.value();

            // Note: queryParams is unmodifiable!!!
            var queryParams = requestContext.getUriInfo().getQueryParameters();
            var originQueryValues = queryParams.get(queryName);
            if (originQueryValues.size() != 1) {
                throw new IllegalStateException("Incorrect size of query values: " + originQueryValues + ", expect only 1.");
            }
            var splitQueryValue = originQueryValues.get(0).split(split.value());
            
            // Error: originQueryValues is unmodifiable!!!
            originQueryValues.clear(); 
            originQueryValues.addAll(Arrays.asList(splitQueryValue));   
        }
    }
}

那么有没有合适的方法来修改过滤器或其他拦截器中的请求参数?

我还尝试使 Set<Scope> 成为一个 class,它接收一个 String 值作为构造函数参数, 但是如何获得将 String 值转换为 Scope 实例而不是调用 Scope.fromString 的转换器?

我认为您不能为此使用过滤器,正是因为不允许过滤器更改参数。您可以使用参数转换器,大致如下所示:

@Provider
public class ScopeConverterProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if(rawType == Set.class) {
            for (Annotation annotation : annotations) {
                if (annotation.annotationType().equals(Split.class)) {
                    return (ParamConverter<T>) new ScopeConverter(((Split) annotation).value());
                }
            }
            return (ParamConverter<T>) new ScopeConverter(" ");// default if there's no @Split annotation
        }
        return null;
    }

}

public class ScopeConverter implements ParamConverter<Set<Scope>> {

    private final String splitCharacter;

    public ScopeConverter(String splitCharacter) {
        this.splitCharacter = splitCharacter;
    }

    @Override
    public Set<Scope> fromString(String value) {
        // strip the [] that the value gets automatically wrapped in,
        // because the query param is a set
        value = value.substring(1, value.length() - 1);
        String[] splits = value.split(splitCharacter);
        HashSet<Scope> scopes = new HashSet<>();
        for (String split : splits) {
            scopes.add(Scope.fromString(split));
        }
        return scopes;
    }

    @Override
    public String toString(Set<Scope> value) {
        return null;   // unused
    }
}