Search in sources :

Example 1 with SafeLoggingAnnotation

use of com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation in project conjure-java by palantir.

the class ConjureUndertowEndpointsGenerator method endpoint.

// TODO(ckozak): refactor
@SuppressWarnings("checkstyle:MethodLength")
private static TypeSpec endpoint(ServiceDefinition service, EndpointDefinition endpoint) {
    List<AdditionalField> additionalFields = new ArrayList<>();
    MethodSpec.Builder handlerBuilder = MethodSpec.methodBuilder("handleRequest").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).addParameter(HttpServerExchange.class, EXCHANGE_NAME).addException(Exception.class);
    ReturnType returnType = endpoint.returns();
    TypeName responseTypeName = returnType.asyncInnerType().orElseGet(returnType::returnType).box();
    if (usesRequestContext(endpoint)) {
        handlerBuilder.addStatement("$T $N = this.$N.contexts().createContext($N, this)", RequestContext.class, REQUEST_CONTEXT, RUNTIME_NAME, EXCHANGE_NAME);
    }
    endpoint.arguments().forEach(def -> def.paramType().match(new Cases<Void>() {

        @Override
        public Void body(CodeBlock deserializerFactory, String deserializerFieldName) {
            TypeName requestBodyType = def.argType().match(ArgTypeTypeName.INSTANCE).box();
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), requestBodyType), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = $L.deserializer(new $T<$T>() {}, $N, this)", deserializerFieldName, deserializerFactory, TypeMarker.class, requestBodyType, RUNTIME_NAME).build()).build());
            return null;
        }

        @Override
        public Void header(String variableName, String headerName, String deserializerFieldName, CodeBlock deserializerFactory, SafeLoggingAnnotation safeLoggable) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T<>($S, $L)", deserializerFieldName, HeaderParamDeserializer.class, headerName, deserializerFactory).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, variableName, invokeDeserializer(def));
            getSafeLogging(headerName, variableName, safeLoggable).ifPresent(handlerBuilder::addStatement);
            return null;
        }

        @Override
        public Void path(String paramName, String deserializerFieldName, CodeBlock deserializerFactory, SafeLoggingAnnotation safeLoggable) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T<>($S, $L)", deserializerFieldName, PathParamDeserializer.class, paramName, deserializerFactory).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, paramName, invokeDeserializer(def));
            getSafeLogging(paramName, paramName, safeLoggable).ifPresent(handlerBuilder::addStatement);
            return null;
        }

        @Override
        public Void pathMulti(String paramName, String deserializerFieldName, CodeBlock deserializerFactory, SafeLoggingAnnotation safeLoggable) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T<>($S, $L)", deserializerFieldName, PathMultiParamDeserializer.class, "*", deserializerFactory).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, paramName, invokeDeserializer(def));
            getSafeLogging(paramName, paramName, safeLoggable).ifPresent(handlerBuilder::addStatement);
            return null;
        }

        @Override
        public Void query(String variableName, String paramName, String deserializerFieldName, CodeBlock deserializerFactory, SafeLoggingAnnotation safeLoggable) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T<>($S, $L)", deserializerFieldName, QueryParamDeserializer.class, paramName, deserializerFactory).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, variableName, invokeDeserializer(def));
            getSafeLogging(paramName, variableName, safeLoggable).ifPresent(handlerBuilder::addStatement);
            return null;
        }

        @Override
        public Void cookie(String variableName, String cookieName, String deserializerFieldName, CodeBlock deserializerFactory, SafeLoggingAnnotation safeLoggable) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T<>($S, $L)", deserializerFieldName, CookieDeserializer.class, cookieName, deserializerFactory).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, variableName, invokeDeserializer(def));
            getSafeLogging(cookieName, variableName, safeLoggable).ifPresent(handlerBuilder::addStatement);
            return null;
        }

        @Override
        public Void authCookie(String variableName, String cookieName, String deserializerFieldName) {
            TypeName paramType = def.argType().match(ArgTypeTypeName.INSTANCE);
            additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Deserializer.class), paramType.box()), deserializerFieldName, Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = new $T(runtime, $S)", deserializerFieldName, BearerTokenCookieDeserializer.class, cookieName).build()).build());
            handlerBuilder.addStatement("$T $N = $L", paramType, variableName, invokeDeserializer(def));
            return null;
        }

        @Override
        public Void authHeader(String variableName) {
            handlerBuilder.addStatement("$T $N = $L", AuthHeader.class, variableName, invokeDeserializer(def));
            return null;
        }

        @Override
        public Void exchange() {
            return null;
        }

        @Override
        public Void context() {
            return null;
        }
    }));
    if (returnType.asyncInnerType().isEmpty() && returnType.isVoid()) {
        handlerBuilder.addStatement(invokeDelegate(endpoint)).addStatement("$N.setStatusCode($T.NO_CONTENT)", EXCHANGE_NAME, StatusCodes.class);
    } else {
        additionalFields.add(ImmutableAdditionalField.builder().field(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Serializer.class), responseTypeName), returnType.serializerFieldName(), Modifier.PRIVATE, Modifier.FINAL).build()).constructorInitializer(CodeBlock.builder().addStatement("this.$N = $L.serializer(new $T<$T>() {}, $N, this)", returnType.serializerFieldName(), returnType.serializerFactory(), TypeMarker.class, responseTypeName, RUNTIME_NAME).build()).build());
        if (returnType.asyncInnerType().isPresent()) {
            handlerBuilder.addStatement("$N.async().register($L, this, $N)", RUNTIME_NAME, invokeDelegate(endpoint), EXCHANGE_NAME);
        } else {
            handlerBuilder.addStatement("write($L, $N)", invokeDelegate(endpoint), EXCHANGE_NAME);
        }
    }
    TypeSpec.Builder endpointBuilder = TypeSpec.classBuilder(endpointClassName(endpoint.endpointName())).addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).addSuperinterface(HttpHandler.class).addSuperinterface(Endpoint.class).addField(UndertowRuntime.class, RUNTIME_NAME, Modifier.PRIVATE, Modifier.FINAL).addField(service.serviceInterface(), DELEGATE_NAME, Modifier.PRIVATE, Modifier.FINAL).addFields(additionalFields.stream().map(AdditionalField::field).collect(ImmutableList.toImmutableList())).addMethod(MethodSpec.constructorBuilder().addParameter(UndertowRuntime.class, RUNTIME_NAME).addParameter(service.serviceInterface(), DELEGATE_NAME).addStatement("this.$1N = $1N", RUNTIME_NAME).addStatement("this.$1N = $1N", DELEGATE_NAME).addCode(additionalFields.stream().map(AdditionalField::constructorInitializer).collect(CodeBlock.joining(""))).build()).addMethod(handlerBuilder.build());
    if (!TypeName.VOID.equals(returnType.returnType())) {
        endpointBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(ReturnValueWriter.class), responseTypeName));
        endpointBuilder.addMethod(MethodSpec.methodBuilder("write").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).addParameter(responseTypeName, RETURN_VALUE).addParameter(HttpServerExchange.class, EXCHANGE_NAME).addException(IOException.class).addStatement("this.$N.serialize($N, $N)", returnType.serializerFieldName(), RETURN_VALUE, EXCHANGE_NAME).build());
    }
    return endpointBuilder.addMethod(MethodSpec.methodBuilder("method").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(HttpString.class).addStatement("return $T.$N", Methods.class, endpoint.httpMethod().name()).build()).addMethod(MethodSpec.methodBuilder("template").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(String.class).addStatement("return $S", endpoint.httpPath().path()).build()).addMethod(MethodSpec.methodBuilder("serviceName").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(String.class).addStatement("return $S", endpoint.serviceName().get()).build()).addMethod(MethodSpec.methodBuilder("name").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(String.class).addStatement("return $S", endpoint.endpointName().get()).build()).addMethod(MethodSpec.methodBuilder("handler").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(HttpHandler.class).addStatement("return this").build()).build();
}
Also used : ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName) TypeName(com.squareup.javapoet.TypeName) MethodSpec(com.squareup.javapoet.MethodSpec) SafeLoggingAnnotation(com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation) ArrayList(java.util.ArrayList) CodeBlock(com.squareup.javapoet.CodeBlock) HttpString(io.undertow.util.HttpString) IOException(java.io.IOException) ReturnType(com.palantir.conjure.java.undertow.processor.data.ReturnType) HttpServerExchange(io.undertow.server.HttpServerExchange) Endpoint(com.palantir.conjure.java.undertow.lib.Endpoint) CookieDeserializer(com.palantir.conjure.java.undertow.annotations.CookieDeserializer) PathMultiParamDeserializer(com.palantir.conjure.java.undertow.annotations.PathMultiParamDeserializer) BearerTokenCookieDeserializer(com.palantir.conjure.java.undertow.annotations.BearerTokenCookieDeserializer) PathParamDeserializer(com.palantir.conjure.java.undertow.annotations.PathParamDeserializer) HeaderParamDeserializer(com.palantir.conjure.java.undertow.annotations.HeaderParamDeserializer) Deserializer(com.palantir.conjure.java.undertow.lib.Deserializer) QueryParamDeserializer(com.palantir.conjure.java.undertow.annotations.QueryParamDeserializer) UndertowRuntime(com.palantir.conjure.java.undertow.lib.UndertowRuntime) Cases(com.palantir.conjure.java.undertow.processor.data.ParameterType.Cases) Methods(io.undertow.util.Methods) Serializer(com.palantir.conjure.java.undertow.lib.Serializer) TypeSpec(com.squareup.javapoet.TypeSpec)

Example 2 with SafeLoggingAnnotation

use of com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation in project conjure-java by palantir.

the class ParamTypesResolver method getParameterType.

@SuppressWarnings("CyclomaticComplexity")
public Optional<ParameterType> getParameterType(VariableElement variableElement) {
    List<AnnotationMirror> paramAnnotationMirrors = new ArrayList<>();
    for (AnnotationMirror annotationMirror : variableElement.getAnnotationMirrors()) {
        TypeElement annotationTypeElement = MoreElements.asType(annotationMirror.getAnnotationType().asElement());
        if (SUPPORTED_ANNOTATIONS.contains(annotationTypeElement.getQualifiedName().toString())) {
            paramAnnotationMirrors.add(annotationMirror);
        }
    }
    List<AnnotationReflector> annotationReflectors = paramAnnotationMirrors.stream().map(ImmutableAnnotationReflector::of).collect(Collectors.toList());
    boolean isSafe = annotationReflectors.stream().anyMatch(annotation -> annotation.isAnnotation(Safe.class));
    boolean isUnsafe = annotationReflectors.stream().anyMatch(annotation -> annotation.isAnnotation(Unsafe.class));
    SafeLoggingAnnotation safeLoggable = isUnsafe ? SafeLoggingAnnotation.UNSAFE : isSafe ? SafeLoggingAnnotation.SAFE : SafeLoggingAnnotation.UNKNOWN;
    List<AnnotationReflector> otherAnnotationReflectors = annotationReflectors.stream().filter(annotation -> !annotation.isAnnotation(Safe.class) && !annotation.isAnnotation(Unsafe.class)).collect(Collectors.toList());
    if (otherAnnotationReflectors.isEmpty()) {
        if (!safeLoggable.equals(SafeLoggingAnnotation.UNKNOWN)) {
            context.reportError("Parameter type cannot be annotated with safe logging annotations", variableElement, SafeArg.of("type", variableElement.asType()));
            return Optional.empty();
        }
        if (context.isSameTypes(variableElement.asType(), AuthHeader.class)) {
            return Optional.of(ParameterTypes.authHeader(variableElement.getSimpleName().toString()));
        } else if (context.isSameTypes(variableElement.asType(), HttpServerExchange.class)) {
            return Optional.of(ParameterTypes.exchange());
        } else if (context.isSameTypes(variableElement.asType(), RequestContext.class)) {
            return Optional.of(ParameterTypes.context());
        } else {
            context.reportError("At least one annotation should be present or type should be InputStream", variableElement, SafeArg.of("requestBody", InputStream.class), SafeArg.of("supportedAnnotations", PARAM_ANNOTATION_CLASSES));
            return Optional.empty();
        }
    }
    if (otherAnnotationReflectors.size() > 1) {
        context.reportError("Only single annotation can be used", variableElement, SafeArg.of("annotations", otherAnnotationReflectors));
        return Optional.empty();
    }
    // TODO(ckozak): More validation of values.
    AnnotationReflector annotationReflector = Iterables.getOnlyElement(otherAnnotationReflectors);
    if (annotationReflector.isAnnotation(Handle.Body.class)) {
        return Optional.of(bodyParameter(variableElement, annotationReflector));
    } else if (annotationReflector.isAnnotation(Handle.Header.class)) {
        return Optional.of(headerParameter(variableElement, annotationReflector, safeLoggable));
    } else if (annotationReflector.isAnnotation(Handle.PathParam.class)) {
        return Optional.of(pathParameter(variableElement, annotationReflector, safeLoggable));
    } else if (annotationReflector.isAnnotation(Handle.PathMultiParam.class)) {
        return Optional.of(pathMultiParameter(variableElement, annotationReflector, safeLoggable));
    } else if (annotationReflector.isAnnotation(Handle.QueryParam.class)) {
        return Optional.of(queryParameter(variableElement, annotationReflector, safeLoggable));
    } else if (annotationReflector.isAnnotation(Handle.Cookie.class)) {
        return cookieParameter(variableElement, annotationReflector, safeLoggable);
    }
    throw new SafeIllegalStateException("Not possible");
}
Also used : SafeLoggingAnnotation(com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation) Iterables(com.google.common.collect.Iterables) SafeIllegalStateException(com.palantir.logsafe.exceptions.SafeIllegalStateException) HttpServerExchange(io.undertow.server.HttpServerExchange) VariableElement(javax.lang.model.element.VariableElement) AuthHeader(com.palantir.tokens.auth.AuthHeader) TypeElement(javax.lang.model.element.TypeElement) RequestContext(com.palantir.conjure.java.undertow.lib.RequestContext) ArrayList(java.util.ArrayList) SafeArg(com.palantir.logsafe.SafeArg) BearerToken(com.palantir.tokens.auth.BearerToken) CodeBlock(com.squareup.javapoet.CodeBlock) Handle(com.palantir.conjure.java.undertow.annotations.Handle) MoreElements(com.google.auto.common.MoreElements) ImmutableSet(com.google.common.collect.ImmutableSet) ContainerType(com.palantir.conjure.java.undertow.processor.data.DefaultDecoderNames.ContainerType) Set(java.util.Set) Collectors(java.util.stream.Collectors) AnnotationMirror(javax.lang.model.element.AnnotationMirror) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) Safe(com.palantir.logsafe.Safe) Stream(java.util.stream.Stream) Unsafe(com.palantir.logsafe.Unsafe) Optional(java.util.Optional) DefaultParamDecoder(com.palantir.conjure.java.undertow.annotations.DefaultParamDecoder) InputStream(java.io.InputStream) SafeLoggingAnnotation(com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation) TypeElement(javax.lang.model.element.TypeElement) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) Unsafe(com.palantir.logsafe.Unsafe) Safe(com.palantir.logsafe.Safe) Handle(com.palantir.conjure.java.undertow.annotations.Handle) HttpServerExchange(io.undertow.server.HttpServerExchange) AnnotationMirror(javax.lang.model.element.AnnotationMirror) AuthHeader(com.palantir.tokens.auth.AuthHeader) SafeIllegalStateException(com.palantir.logsafe.exceptions.SafeIllegalStateException)

Aggregations

SafeLoggingAnnotation (com.palantir.conjure.java.undertow.processor.data.ParameterType.SafeLoggingAnnotation)2 CodeBlock (com.squareup.javapoet.CodeBlock)2 HttpServerExchange (io.undertow.server.HttpServerExchange)2 ArrayList (java.util.ArrayList)2 MoreElements (com.google.auto.common.MoreElements)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 Iterables (com.google.common.collect.Iterables)1 BearerTokenCookieDeserializer (com.palantir.conjure.java.undertow.annotations.BearerTokenCookieDeserializer)1 CookieDeserializer (com.palantir.conjure.java.undertow.annotations.CookieDeserializer)1 DefaultParamDecoder (com.palantir.conjure.java.undertow.annotations.DefaultParamDecoder)1 Handle (com.palantir.conjure.java.undertow.annotations.Handle)1 HeaderParamDeserializer (com.palantir.conjure.java.undertow.annotations.HeaderParamDeserializer)1 PathMultiParamDeserializer (com.palantir.conjure.java.undertow.annotations.PathMultiParamDeserializer)1 PathParamDeserializer (com.palantir.conjure.java.undertow.annotations.PathParamDeserializer)1 QueryParamDeserializer (com.palantir.conjure.java.undertow.annotations.QueryParamDeserializer)1 Deserializer (com.palantir.conjure.java.undertow.lib.Deserializer)1 Endpoint (com.palantir.conjure.java.undertow.lib.Endpoint)1 RequestContext (com.palantir.conjure.java.undertow.lib.RequestContext)1 Serializer (com.palantir.conjure.java.undertow.lib.Serializer)1 UndertowRuntime (com.palantir.conjure.java.undertow.lib.UndertowRuntime)1