@Override public Class<V> getType() { return argument.getType(); }
@Override public boolean equalsType(Argument<?> o) { if (this == o) { return true; } if (o == null) { return false; } return Objects.equals(type, o.getType()) && Objects.equals(typeParameters, o.getTypeVariables()); }
/** * Returns the string representation of the argument type, including generics. * * @param simple If true, output the simple name of types * @return The type string representation */ default String getTypeString(boolean simple) { Class<T> type = getType(); StringBuilder returnType = new StringBuilder(simple ? type.getSimpleName() : type.getName()); Map<String, Argument<?>> generics = getTypeVariables(); if (!generics.isEmpty()) { returnType .append("<") .append(generics.values() .stream() .map(arg -> arg.getTypeString(simple)) .collect(Collectors.joining(", "))) .append(">"); } return returnType.toString(); }
private void reportArguments(Argument... arguments) { if (ArrayUtils.isNotEmpty(arguments)) { for (Argument argument : arguments) { final Class argType = argument.getType(); if (!ClassUtils.isJavaLangType(argType)) { ClassLoadingReporter.reportBeanPresent(argType); } reportArguments(argument.getTypeParameters()); } } } }
@Override public <T> Optional<T> get(K name, ArgumentConversionContext<T> conversionContext) { Object v = map.get(name); if (v == null) { return Optional.empty(); } Argument<T> argument = conversionContext.getArgument(); if (argument.getType().isInstance(v)) { return Optional.of((T) v); } return ConversionService.SHARED.convert(v, conversionContext); }
/** * Convert an argument array to a class array. * * @param arguments The arguments * @return The class array */ static Class[] toClassArray(Argument... arguments) { if (ArrayUtils.isEmpty(arguments)) { return ReflectionUtils.EMPTY_CLASS_ARRAY; } Class[] types = new Class[arguments.length]; for (int i = 0; i < arguments.length; i++) { Argument argument = arguments[i]; types[i] = argument.getType(); } return types; }
private Map<Argument<?>, Object> prepareBoundVariables(ExecutableMethod<?, ?> executable, List<?> parameters) { Map<Argument<?>, Object> preBound = new HashMap<>(executable.getArguments().length); for (Argument argument : executable.getArguments()) { Class type = argument.getType(); for (Object object : parameters) { if (type.isInstance(object)) { preBound.put(argument, object); break; } } } return preBound; }
private boolean isResponsePublisher(ReturnType<?> genericReturnType, Class<?> javaReturnType) { return Publishers.isConvertibleToPublisher(javaReturnType) && genericReturnType.getFirstTypeVariable().map(arg -> HttpResponse.class.isAssignableFrom(arg.getType())).orElse(false); }
/** * Convert the value and return a binding result. * * @param value The value to convert * @param context The conversion context * @return The binding result */ protected BindingResult<T> doConvert(Object value, ArgumentConversionContext<T> context) { Optional<T> result = conversionService.convert(value, context); if (result.isPresent() && context.getArgument().getType() == Optional.class) { return () -> (Optional<T>) result.get(); } return () -> result; } }
/** * Attempts to convert the given object to the given target type. If conversion fails or is not possible an empty {@link Optional} is returned. * * @param object The object to convert * @param context The {@link ArgumentConversionContext} * @param <T> The generic type * @return The optional */ default <T> Optional<T> convert(Object object, ArgumentConversionContext<T> context) { return convert(object, context.getArgument().getType(), context); } }
/** * Attempts to convert the given object to the given target type. If conversion fails or is not possible an empty {@link Optional} is returned. * * @param object The object to convert * @param targetType The target type * @param <T> The generic type * @return The optional */ default <T> Optional<T> convert(Object object, Argument<T> targetType) { return convert(object, targetType.getType(), ConversionContext.of(targetType)); }
@SuppressWarnings("unchecked") @Override public <T1> Optional<T1> getBody(Argument<T1> type) { Optional<T> body = getBody(); return body.flatMap(t -> convertedBodies.computeIfAbsent(type.getType(), aClass -> conversionService.convert(t, ConversionContext.of(type)))); }
@Override protected void doOnComplete() { Optional<Argument<?>> firstTypeParameter = context.getFirstTypeVariable(); Optional body = nettyHttpRequest.getBody(); if (body.isPresent()) { if (firstTypeParameter.isPresent()) { Argument<?> arg = firstTypeParameter.get(); Class targetType = arg.getType(); Optional converted = conversionService.convert(body.get(), context.with(arg)); if (converted.isPresent()) { future.complete(converted.get()); } else { future.completeExceptionally(new IllegalArgumentException("Cannot bind JSON to argument type: " + targetType.getName())); } } else { future.complete(body.get()); } } else { future.complete(null); } } });
private Object decodeContext( ConversionService<?> conversionService, Argument<?> arg, Object context) { if (ClassUtils.isJavaLangType(arg.getType())) { Object convert = doConvertInput(conversionService, arg, context); if (convert != null) { return convert; } } throw new CodecException("Unable to decode argument from stream: " + arg); }
@SuppressWarnings("unchecked") @Override public <T> Optional<T> getBody(Argument<T> type) { return convertedBodies.computeIfAbsent(type.getType(), aClass -> getBody().flatMap(b -> { ArgumentConversionContext<T> context = ConversionContext.of(type); if (b instanceof ByteBuffer) { return conversionService.convert(((ByteBuffer) b).asNativeBuffer(), context); } return conversionService.convert(b, context); })); }
@Override public <T> Optional<ArgumentBinder<T, HttpRequest<?>>> findArgumentBinder(Argument<T> argument, HttpRequest<?> source) { Optional<Class<? extends Annotation>> opt = argument.getAnnotationMetadata().getAnnotationTypeByStereotype(Bindable.class); if (opt.isPresent()) { Class<? extends Annotation> annotationType = opt.get(); RequestArgumentBinder<T> binder = findBinder(argument, annotationType); if (binder == null) { binder = byAnnotation.get(annotationType); } if (binder != null) { return Optional.of(binder); } } else { RequestArgumentBinder<T> binder = byType.get(argument.typeHashCode()); if (binder != null) { return Optional.of(binder); } else { binder = byType.get(Argument.of(argument.getType()).typeHashCode()); if (binder != null) { return Optional.of(binder); } } } return Optional.of(new ParameterAnnotationBinder<>(conversionService)); }
/** * Perform an HTTP request for the given request object emitting the full HTTP response from returned * {@link org.reactivestreams.Publisher} and converting the response body to the specified type. * * @param request The {@link HttpRequest} to execute * @param bodyType The body type * @param errorType The error type * @param <I> The request body type * @param <O> The response body type * @param <E> The error type * @return A result of the given type or null the URI returns a 404 * @throws HttpClientResponseException if an error status is returned */ @SuppressWarnings("unchecked") default <I, O, E> O retrieve(HttpRequest<I> request, Argument<O> bodyType, Argument<E> errorType) { HttpResponse<O> response = exchange(request, bodyType, errorType); if (HttpStatus.class.isAssignableFrom(bodyType.getType())) { return (O) response.getStatus(); } else { return response .getBody() .orElseThrow(() -> new HttpClientResponseException( "Empty body", response )); } }
private Object decodeInputArgument( ConversionService<?> conversionService, LocalFunctionRegistry localFunctionRegistry, Argument<?> arg, InputStream input) { Class<?> argType = arg.getType(); ClassLoadingReporter.reportBeanPresent(argType); if (ClassUtils.isJavaLangType(argType)) { Object converted = doConvertInput(conversionService, arg, input); if (converted != null) { return converted; } } else if (argType.isInstance(input)) { return input; } else { if (localFunctionRegistry instanceof MediaTypeCodecRegistry) { Optional<MediaTypeCodec> registeredDecoder = ((MediaTypeCodecRegistry) localFunctionRegistry).findCodec(MediaType.APPLICATION_JSON_TYPE); if (registeredDecoder.isPresent()) { MediaTypeCodec decoder = registeredDecoder.get(); return decoder.decode(arg, input); } } } throw new CodecException("Unable to decode argument from stream: " + arg); }
/** * Perform an HTTP request for the given request object emitting the full HTTP response from returned * {@link Publisher} and converting the response body to the specified type. * * @param request The {@link HttpRequest} to execute * @param bodyType The body type * @param errorType The error type * @param <I> The request body type * @param <O> The response body type * @param <E> The error type * @return A {@link Publisher} that emits a result of the given type */ default <I, O, E> Publisher<O> retrieve(HttpRequest<I> request, Argument<O> bodyType, Argument<E> errorType) { return Publishers.map(exchange(request, bodyType, errorType), response -> { if (bodyType.getType() == HttpStatus.class) { return (O) response.getStatus(); } else { Optional<O> body = response.getBody(); return body .orElseThrow(() -> new HttpClientResponseException( "Empty body", response )); } }); }
@Override public O invoke(FunctionDefinition definition, I input, Argument<O> outputType) { if (!(definition instanceof AWSInvokeRequestDefinition)) { throw new IllegalArgumentException("Function definition must be a AWSInvokeRequestDefinition"); } InvokeRequest invokeRequest = ((AWSInvokeRequestDefinition) definition).getInvokeRequest().clone(); boolean isReactiveType = Publishers.isConvertibleToPublisher(outputType.getType()); if (isReactiveType) { Flowable<Object> invokeFlowable = Flowable.just(invokeRequest) .flatMap(req -> { encodeInput(input, invokeRequest); Future<InvokeResult> future = asyncClient.invokeAsync(req); return Flowable.fromFuture(future, Schedulers.from(ioExecutor)); }) .map(invokeResult -> decodeResult(definition, (Argument<O>) outputType.getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT), invokeResult)); invokeFlowable = invokeFlowable.onErrorResumeNext(throwable -> { return Flowable.error(new FunctionExecutionException("Error executing AWS Lambda [" + definition.getName() + "]: " + throwable.getMessage(), throwable)); }); return ConversionService.SHARED.convert(invokeFlowable, outputType).orElseThrow(() -> new IllegalArgumentException("Unsupported Reactive type: " + outputType)); } else { encodeInput(input, invokeRequest); InvokeResult invokeResult = asyncClient.invoke(invokeRequest); try { return (O) decodeResult(definition, outputType, invokeResult); } catch (Exception e) { throw new FunctionExecutionException("Error executing AWS Lambda [" + definition.getName() + "]: " + e.getMessage(), e); } } }