All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.jubic.easyconfig.internal.initializers.BuilderClassInitializerParser Maven / Gradle / Ivy

There is a newer version: 0.10.4
Show newest version
package fi.jubic.easyconfig.internal.initializers;

import fi.jubic.easyconfig.annotations.EasyConfig;
import fi.jubic.easyconfig.internal.ConfigPropertyDef;
import fi.jubic.easyconfig.internal.MappingContext;
import fi.jubic.easyconfig.internal.Result;
import fi.jubic.easyconfig.internal.parameter.Mappable;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class BuilderClassInitializerParser implements InitializerParser {
    @Override
    public  Optional>> parse(
            MappingContext context,
            ConfigPropertyDef propertyDef
    ) {
        Class propertyClass = propertyDef.getPropertyClass();

        EasyConfig easyConfig = propertyClass.getAnnotation(EasyConfig.class);
        if (easyConfig == null) return Optional.empty();
        if (easyConfig.builder().equals(Void.class)) return Optional.empty();

        Class builderClass = easyConfig.builder();

        MappingContext currentContext = context.push(
                String.format(
                        "%s (builder initializer %s)",
                        propertyClass.getCanonicalName(),
                        builderClass.getCanonicalName()
                )
        );

        Result> builderConstructor = Stream.of(builderClass.getConstructors())
                .filter(constructor -> constructor.getParameterCount() == 0)
                .findFirst()
                .map(Result::>of)
                .orElseGet(() -> Result.message(
                        currentContext.format("No default constructor found")
                ));


        Result buildMethod = Stream.of(builderClass.getMethods())
                .filter(method -> method.getParameterCount() == 0)
                .filter(method -> method.getReturnType().equals(propertyClass))
                .findFirst()
                .map(Result::of)
                .orElseGet(() -> Result.message(
                        currentContext.format("No build method found")
                ));

        Result> setters = Optional
                .of(
                        Stream.of(builderClass.getMethods())
                                .filter(method -> SUPPORTED_PROPERTY_ANNOTATIONS.stream()
                                        .map(method::getAnnotation)
                                        .anyMatch(Objects::nonNull)
                                )
                                .filter(method -> method.getReturnType().equals(builderClass))
                                .filter(method -> method.getParameterCount() == 1)
                                .collect(Collectors.toList())
                )
                .filter(foundSetters -> !foundSetters.isEmpty())
                .map(Result::of)
                .orElseGet(() -> Result.message(
                        currentContext.format("No setter methods found")
                ));

        if (
                builderConstructor.hasMessages()
                        || buildMethod.hasMessages()
                        || setters.hasMessages()
        ) {
            return Optional.of(
                    Result.unwrapMessages(builderConstructor, buildMethod, setters)
            );
        }

        Result>> parametersResult = setters.getValue()
                .stream()
                .map(setter -> {
                    Parameter parameter = setter.getParameters()[0];
                    return PARAMETER_PARSER
                            .parseParameter(
                                    currentContext.subContext(),
                                    ConfigPropertyDef.buildForParameter(parameter, setter)
                                            .orElseThrow(IllegalStateException::new)
                            )
                            .orElseGet(() -> Result.message(
                                    currentContext.format(
                                            String.format(
                                                    "No parser found for %s",
                                                    parameter.getClass().getCanonicalName()
                                            )
                                    )
                            ));
                })
                .collect(
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                Result::unwrap
                        )
                );

        Result> initializer = parametersResult.map(
                parameters -> (prefix, envProvider) -> Result
                        .unwrap(
                                parameters.stream()
                                        .map(parameter -> parameter.initialize(prefix, envProvider))
                                        .collect(Collectors.toList())
                        )
                        .flatMap(initializerParameters -> {
                            MappingContext initializationContext = new MappingContext(
                                    String.format(
                                            "%s (builder initializer %s)",
                                            propertyClass.getCanonicalName(),
                                            builderClass.getCanonicalName()
                                    )
                            );
                            Object builder;
                            try {
                                builder = builderConstructor.getValue().newInstance();
                            }
                            catch (InstantiationException
                                    | IllegalAccessException
                                    | InvocationTargetException e
                            ) {
                                return Result.message(
                                        initializationContext.format(
                                                "Could not initialize the builder"
                                        ),
                                        e
                                );
                            }

                            for (int i = 0; i < initializerParameters.size(); i++) {
                                try {
                                    builder = setters.getValue()
                                            .get(i)
                                            .invoke(
                                                    builder,
                                                    initializerParameters.get(i)
                                            );
                                }
                                catch (IllegalAccessException | InvocationTargetException e) {
                                    return Result.message(
                                            initializationContext.format(
                                                    String.format(
                                                            "Could not invoke setter %s",
                                                            setters.getValue().get(i).getName()
                                                    )

                                            ),
                                            e
                                    );
                                }

                            }

                            try {
                                //noinspection unchecked
                                return Result.of((T) buildMethod.getValue().invoke(builder));
                            }
                            catch (IllegalAccessException | InvocationTargetException e) {
                                return Result.message(
                                        initializationContext.format(
                                                "Could not invoke build method"
                                        ),
                                        e
                                );
                            }
                        })
        );
        return Optional.of(initializer);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy