private TypeSpecHolder generateParser()

in dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java [369:662]


    private TypeSpecHolder generateParser(ClassInfo info) {
        final ClassName targetType = ClassName.get(info.name().prefix().toString(), info.name().withoutPackagePrefix());
        final TypeSpec.Builder builder = TypeSpec.classBuilder(info.simpleName() + "Deserializer");
        final Map<String, Set<String>> attributes = new HashMap<>();
        final List<AnnotationSpec> properties = new ArrayList<>();
        final AnnotationSpec.Builder yamlTypeAnnotation = AnnotationSpec.builder(CN_YAML_TYPE);

        builder.addModifiers(Modifier.PUBLIC, Modifier.STATIC);

        if (extendsType(info, SEND_DEFINITION_CLASS) || extendsType(info, TO_DYNAMIC_DEFINITION_CLASS)
                || extendsType(info, POLL_DEFINITION_CLASS)) {
            builder.superclass(ParameterizedTypeName.get(CN_ENDPOINT_AWARE_DESERIALIZER_BASE, targetType));
        } else {
            builder.superclass(ParameterizedTypeName.get(CN_DESERIALIZER_BASE, targetType));
        }

        TypeSpecHolder.put(attributes, "type", info.name().toString());

        //TODO: add an option on Camel's definitions to distinguish between IN/OUT types
        if (info.name().toString().equals("org.apache.camel.model.InterceptDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.InterceptFromDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.InterceptSendToEndpointDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.OnExceptionDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.OnCompletionDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.rest.RestDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }
        if (info.name().toString().equals("org.apache.camel.model.rest.RestConfigurationDefinition")) {
            builder.addAnnotation(CN_YAML_IN);
        }

        final AtomicReference<String> modelName = new AtomicReference<>();
        annotationValue(info, XML_ROOT_ELEMENT_ANNOTATION_CLASS, "name")
                .map(AnnotationValue::asString)
                .filter(value -> !"##default".equals(value))
                .ifPresent(value -> {
                    // generate the kebab case variant for backward compatibility
                    // https://issues.apache.org/jira/browse/CAMEL-17097
                    if (!Objects.equals(value, StringHelper.camelCaseToDash(value))) {
                        yamlTypeAnnotation.addMember("nodes", "$S", StringHelper.camelCaseToDash(value));
                        TypeSpecHolder.put(attributes, "node", StringHelper.camelCaseToDash(value));
                    }

                    yamlTypeAnnotation.addMember("nodes", "$S", value);
                    modelName.set(value);
                    TypeSpecHolder.put(attributes, "node", value);
                });

        //
        // Constructors
        //
        builder.addMethod(MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addStatement("super($L.class)", info.simpleName())
                .build());

        //
        // T handledTypeInstance();
        //
        builder.addMethod(MethodSpec.methodBuilder("newInstance")
                .addAnnotation(AnnotationSpec.builder(Override.class).build())
                .addModifiers(Modifier.PROTECTED)
                .returns(targetType)
                .addCode(
                        CodeBlock.builder()
                                .addStatement("return new $L()", info.simpleName())
                                .build())
                .build());

        //
        // T handledTypeInstance(String value);
        //
        for (MethodInfo ctor : info.constructors()) {

            // do not generate inline for error handlers (only ref error handler is allowed)
            boolean eh = implementType(info, ERROR_HANDLER_DEFINITION_CLASS);
            boolean ref = eh && implementType(info, REF_ERROR_HANDLER_DEFINITION_CLASS);
            if (eh && !ref) {
                break;
            }

            if (ctor.parameterTypes().size() == 1 && ctor.parameterTypes().get(0).name().equals(STRING_CLASS)) {
                if ((ctor.flags() & java.lang.reflect.Modifier.PUBLIC) == 0) {
                    break;
                }

                yamlTypeAnnotation.addMember("inline", "true");

                builder
                        .addMethod(MethodSpec.methodBuilder("newInstance")
                                .addAnnotation(AnnotationSpec.builder(Override.class).build())
                                .addModifiers(Modifier.PROTECTED)
                                .addParameter(String.class, "value")
                                .returns(targetType)
                                .addCode(
                                        CodeBlock.builder()
                                                .addStatement("return new $L(value)", info.simpleName())
                                                .build())
                                .build());
                break;
            }
        }

        //
        // Generate setProperty body
        //
        boolean caseAdded = false;

        CodeBlock.Builder setProperty = CodeBlock.builder();
        setProperty.addStatement("propertyKey = org.apache.camel.util.StringHelper.dashToCamelCase(propertyKey)");
        setProperty.beginControlFlow("switch(propertyKey)");

        final Schema descriptor = schemes.computeIfAbsent(
                info.name().toString(),
                k -> new Schema(MAPPER.createObjectNode(), MAPPER.createObjectNode()));

        for (FieldInfo field : fields(info)) {
            if (generateSetValue(descriptor, modelName.get(), setProperty, field, properties)) {
                caseAdded = true;
            }
        }

        if (implementType(info, ID_AWARE_CLASS)) {
            setProperty.beginControlFlow("case $S:", "id");
            setProperty.addStatement("String val = asText(node)");
            setProperty.addStatement("target.setId(val)");
            setProperty.addStatement("break");
            setProperty.endControlFlow();
            setProperty.beginControlFlow("case $S:", "description");
            setProperty.addStatement("String val = asText(node)");
            setProperty.addStatement("target.setDescription(val)");
            setProperty.addStatement("break");
            setProperty.endControlFlow();

            properties.add(
                    YamlProperties.annotation("id", "string")
                            .withDescription(descriptor.description("id"))
                            .withDisplayName(descriptor.displayName("id"))
                            .build());

            properties.add(
                    YamlProperties.annotation("description", "string")
                            .withDescription(descriptor.description("description"))
                            .withDisplayName(descriptor.displayName("description"))
                            .build());
        }

        if (shouldHaveSteps(info)) {
            caseAdded = true;

            setProperty.beginControlFlow("case \"steps\":");
            setProperty.addStatement("setSteps(target, node)");
            setProperty.addStatement("break");
            setProperty.endControlFlow();

            properties.add(
                    yamlProperty(
                            "steps",
                            "array:org.apache.camel.model.ProcessorDefinition"));
        }

        if (extendsType(info, SEND_DEFINITION_CLASS) || extendsType(info, TO_DYNAMIC_DEFINITION_CLASS)
                || extendsType(info, POLL_DEFINITION_CLASS)) {
            setProperty.beginControlFlow("default:");
            setProperty.addStatement("return false");
            setProperty.endControlFlow();

            properties.add(
                    yamlProperty(
                            "parameters",
                            "object"));

            builder.addMethod(MethodSpec.methodBuilder("setEndpointUri")
                    .addAnnotation(AnnotationSpec.builder(Override.class).build())
                    .addModifiers(Modifier.PROTECTED)
                    .addParameter(CamelContext.class, "camelContext")
                    .addParameter(Node.class, "node")
                    .addParameter(targetType, "target")
                    .addParameter(
                            ParameterizedTypeName.get(
                                    ClassName.get(Map.class),
                                    ClassName.get(String.class),
                                    ClassName.get(Object.class)),
                            "parameters")
                    .addCode(
                            CodeBlock.builder()
                                    .addStatement(
                                            "target.setUri(org.apache.camel.dsl.yaml.common.YamlSupport.createEndpointUri(camelContext, node, target.getUri(), parameters))")
                                    .build())
                    .build());
        } else if (implementType(info, HAS_EXPRESSION_TYPE_CLASS)) {
            setProperty.beginControlFlow("default:");
            setProperty.addStatement("$T ed = target.getExpressionType()", CN_EXPRESSION_DEFINITION);
            setProperty.beginControlFlow("if (ed != null)");
            setProperty.addStatement(
                    "throw new org.apache.camel.dsl.yaml.common.exception.DuplicateFieldException(node, propertyName, \"as an expression\")");
            setProperty.endControlFlow();
            setProperty.addStatement("ed = ExpressionDeserializers.constructExpressionType(propertyKey, node)");
            setProperty.beginControlFlow("if (ed != null)");
            setProperty.addStatement("target.setExpressionType(ed)");
            setProperty.nextControlFlow("else");
            setProperty.addStatement("return false");
            setProperty.endControlFlow();
            setProperty.endControlFlow();

            if (!extendsType(info, EXPRESSION_DEFINITION_CLASS)) {
                properties.add(
                        yamlProperty(
                                "__extends",
                                "object:org.apache.camel.model.language.ExpressionDefinition",
                                "expression"));
            }
        } else {
            setProperty.beginControlFlow("default:");
            setProperty.addStatement("return false");
            setProperty.endControlFlow();
        }

        setProperty.endControlFlow();

        if (caseAdded) {
            setProperty.addStatement("return true");
        }

        //
        // setProperty(T target, String propertyKey, String propertyName, Node value) throws Exception
        //
        builder
                .addMethod(MethodSpec.methodBuilder("setProperty")
                        .addAnnotation(AnnotationSpec.builder(Override.class).build())
                        .addModifiers(Modifier.PROTECTED)
                        .addParameter(targetType, "target")
                        .addParameter(String.class, "propertyKey")
                        .addParameter(String.class, "propertyName")
                        .addParameter(Node.class, "node")
                        .returns(boolean.class)
                        .addCode(setProperty.build())
                        .build());

        //
        // YamlType
        //
        yamlTypeAnnotation.addMember(
                "types",
                "$L.class",
                info.name().toString());
        yamlTypeAnnotation.addMember(
                "order",
                "org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1",
                info.name().toString());

        JsonNode yamlTypeDisplayName = descriptor.meta.at("/title");
        if (!yamlTypeDisplayName.isMissingNode() && yamlTypeDisplayName.isTextual()) {
            yamlTypeAnnotation.addMember(
                    "displayName",
                    "$S",
                    yamlTypeDisplayName.textValue());
        }

        JsonNode yamlTypeDescription = descriptor.meta.at("/description");
        if (!yamlTypeDescription.isMissingNode() && yamlTypeDescription.isTextual()) {
            yamlTypeAnnotation.addMember(
                    "description",
                    "$S",
                    yamlTypeDescription.textValue());

        }

        JsonNode yamlTypeDeprecated = descriptor.meta.at("/deprecated");
        if (!yamlTypeDeprecated.isMissingNode() && yamlTypeDeprecated.isBoolean()) {
            yamlTypeAnnotation.addMember(
                    "deprecated",
                    "$L",
                    yamlTypeDeprecated.booleanValue());
        }

        properties.stream().sorted(Comparator.comparing(a -> a.members.get("name").toString())).forEach(spec -> {
            yamlTypeAnnotation.addMember("properties", "$L", spec);
        });

        builder.addAnnotation(yamlTypeAnnotation.build());

        return new TypeSpecHolder(builder.build(), attributes);
    }