001/*
002 * Copyright 2023 the original author or authors.
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * https://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.cuioss.test.valueobjects.util;
017
018import static java.util.Objects.requireNonNull;
019
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import de.cuioss.test.valueobjects.api.property.PropertyBuilderConfig;
028import de.cuioss.test.valueobjects.api.property.PropertyBuilderConfigs;
029import de.cuioss.test.valueobjects.property.PropertyMetadata;
030import de.cuioss.test.valueobjects.property.impl.BuilderMetadata;
031import de.cuioss.test.valueobjects.property.impl.PropertyMetadataImpl;
032import de.cuioss.tools.collect.CollectionBuilder;
033import de.cuioss.tools.reflect.MoreReflection;
034import lombok.experimental.UtilityClass;
035
036/**
037 * Utility class for dealing with and the {@link PropertyBuilderConfig} and
038 * {@link PropertyBuilderConfigs} annotations.
039 *
040 * @author Oliver Wolff
041 */
042@UtilityClass
043public final class BuilderPropertyHelper {
044
045    /**
046     * Checks the given type for the annotation {@link PropertyBuilderConfig} and
047     * {@link PropertyBuilderConfigs} and puts all found in the immutable
048     * {@link List} to be returned
049     *
050     * @param annotated     the class that may or may not provide the annotations,
051     *                      must not be null
052     * @param givenMetadata must not be null
053     * @return immutable {@link List} of found {@link PropertyMetadata} elements
054     *         derived by the annotations.
055     */
056    public static List<PropertyMetadata> handleBuilderPropertyConfigAnnotations(final Class<?> annotated,
057            final List<PropertyMetadata> givenMetadata) {
058        requireNonNull(annotated);
059        final var builder = new CollectionBuilder<PropertyMetadata>();
060
061        extractConfiguredPropertyBuilderConfigs(annotated)
062                .forEach(config -> builder.add(builderPropertyConfigToBuilderMetadata(config, givenMetadata)));
063
064        return builder.toImmutableList();
065    }
066
067    /**
068     * Checks the given type for the annotation {@link PropertyBuilderConfig} and
069     * {@link PropertyBuilderConfigs} and puts all found in the immutable
070     * {@link Set} to be returned
071     *
072     * @param annotated the class that may or may not provide the annotations, must
073     *                  not be null
074     * @return immutable {@link Set} of found {@link PropertyBuilderConfig}
075     *         elements.
076     */
077    public static Set<PropertyBuilderConfig> extractConfiguredPropertyBuilderConfigs(final Class<?> annotated) {
078        requireNonNull(annotated);
079        final var builder = new CollectionBuilder<PropertyBuilderConfig>();
080
081        MoreReflection.extractAllAnnotations(annotated, PropertyBuilderConfigs.class)
082                .forEach(contract -> builder.add(Arrays.asList(contract.value())));
083        MoreReflection.extractAllAnnotations(annotated, PropertyBuilderConfig.class).forEach(builder::add);
084
085        return builder.toImmutableSet();
086    }
087
088    private static PropertyMetadata builderPropertyConfigToBuilderMetadata(final PropertyBuilderConfig config,
089            final Collection<PropertyMetadata> givenMetadata) {
090
091        final Map<String, PropertyMetadata> map = new HashMap<>();
092        givenMetadata.forEach(meta -> map.put(meta.getName(), meta));
093        PropertyHelper.assertPropertyExists(config.name(), map);
094
095        final var metatada = PropertyMetadataImpl.builder(map.get(config.name()))
096                .propertyAccessStrategy(config.propertyAccessStrategy()).build();
097
098        return BuilderMetadata.builder().delegateMetadata(metatada).builderMethodName(config.builderMethodName())
099                .builderMethodPrefix(config.methodPrefix())
100                .builderSingleAddMethodName(config.builderSingleAddMethodName()).build();
101    }
102
103}