samples.builder.AbstractBuilderAnnotation.java Source code

Java tutorial

Introduction

Here is the source code for samples.builder.AbstractBuilderAnnotation.java

Source

/*-
 * #%L
 * utils-commons
 * %%
 * Copyright (C) 2016 - 2018 Gilles Landel
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package samples.builder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;

import fr.landel.utils.commons.builder.EqualsBuilder2;
import fr.landel.utils.commons.builder.HashCodeBuilder2;
import fr.landel.utils.commons.builder.ToStringBuilder;

public abstract class AbstractBuilderAnnotation<T extends AbstractBuilderAnnotation<T>> {

    private static final String EQUALS_ERROR_FIELD = "equals_error_field";
    private static final String GETTER_PREFIX = "get";
    private static final List<Function<AbstractBuilderAnnotation<?>, Object>> EQUALS_FUNCTIONS = new ArrayList<>();
    private static final Map<CharSequence, Function<AbstractBuilderAnnotation<?>, Object>> TOSTRING_FUNCTIONS = new HashMap<>();

    private static boolean analyzed = false;
    private static String name;

    protected AbstractBuilderAnnotation() {
        if (!analyzed) {
            final Class<?> clazz = this.getClass();
            name = clazz.getSimpleName();

            for (Field field : clazz.getDeclaredFields()) {
                for (Annotation annotation : field.getDeclaredAnnotations()) {
                    if (EqualsProperty.class.equals(annotation.annotationType())) {
                        EQUALS_FUNCTIONS.add(getFunction(clazz, field));
                    } else if (ToStringProperty.class.equals(annotation.annotationType())) {
                        TOSTRING_FUNCTIONS.put(field.getName(), getFunction(clazz, field));
                    }
                }
            }

            analyzed = true;
        }
    }

    private static Function<AbstractBuilderAnnotation<?>, Object> getFunction(final Class<?> clazz,
            final Field field) {
        Function<AbstractBuilderAnnotation<?>, Object> function;
        try {
            final Method method = clazz.getDeclaredMethod(GETTER_PREFIX + StringUtils.capitalize(field.getName()));
            function = o -> {
                try {
                    return method.invoke(o);
                } catch (final InvocationTargetException | IllegalArgumentException | IllegalAccessException e) {
                    return EQUALS_ERROR_FIELD;
                }
            };
        } catch (NoSuchMethodException | SecurityException e1) {
            field.setAccessible(true);
            function = o -> {
                try {
                    return field.get(o);
                } catch (final IllegalArgumentException | IllegalAccessException e) {
                    return EQUALS_ERROR_FIELD;
                }
            };
        }
        return function;
    }

    @Override
    public boolean equals(Object obj) {
        final EqualsBuilder2<AbstractBuilderAnnotation<?>> equalsBuilder = new EqualsBuilder2<>(this, obj);

        for (Function<AbstractBuilderAnnotation<?>, Object> function : EQUALS_FUNCTIONS) {
            equalsBuilder.append(function);
        }

        return equalsBuilder.isEqual();
    }

    @Override
    public int hashCode() {
        final HashCodeBuilder2<AbstractBuilderAnnotation<?>> builder = new HashCodeBuilder2<>(this);

        for (Function<AbstractBuilderAnnotation<?>, Object> function : EQUALS_FUNCTIONS) {
            builder.append(function);
        }
        return builder.toHashCode();
    }

    @Override
    public String toString() {
        final ToStringBuilder builder = new ToStringBuilder(name);

        for (Entry<CharSequence, Function<AbstractBuilderAnnotation<?>, Object>> entry : TOSTRING_FUNCTIONS
                .entrySet()) {
            builder.append(entry.getKey(), entry.getValue().apply(this));
        }

        return builder.build();
    }
}