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

net.e6tech.elements.common.reflection.Annotator Maven / Gradle / Ivy

There is a newer version: 2.7.9
Show newest version
/*
 * Copyright 2017 Futeh Kao
 *
 * 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.
 */

package net.e6tech.elements.common.reflection;

import net.e6tech.elements.common.logging.Logger;
import net.e6tech.elements.common.util.SystemException;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;

/**
 * Created by futeh.
 * This class is used to create an instance of Annotation and setting its values.
 * See AnnotationTest for an example
 */
public class Annotator implements InvocationHandler {
    static Map objectMethods = new HashMap<>();

    private Map values;
    private Method lastAccessed;
    private Class type;
    private Integer hashCode;
    private String toString;

    static {
        objectMethods.put("toString", 0);
        objectMethods.put("hashCode", 0);
        objectMethods.put("annotationType", 0);
        objectMethods.put("equals", 1);
    }

    @SuppressWarnings("unchecked")
    protected Annotator(Class type, Map values) {
        this.type = type;
        this.values = values;
    }

    @SuppressWarnings("unchecked")
    public static  T create(Class cls, BiConsumer consumer) {
        return create(cls, null, consumer);
    }

    @SuppressWarnings("unchecked")
    public static  T create(Class cls, T original, BiConsumer consumer) {
        Map values = new LinkedHashMap<>();
        for (Method method : cls.getDeclaredMethods()) {
            if (objectMethods.containsKey(method.getName())
                && method.getParameterCount() == objectMethods.get(method.getName())) {
                // to be generated
            } else {
                Object defaultValue = method.getDefaultValue();
                values.put(method, defaultValue);
            }
        }

        Annotator annotator = new Annotator(cls, values);
        annotator.copyFrom(original);
        AnnotationValue annotationValue = new AnnotationValue(annotator);
        if (consumer != null)
            consumer.accept(annotationValue, (T) Proxy.newProxyInstance(cls.getClassLoader(), new Class[]{cls}, annotator));
        return (T) Proxy.newProxyInstance(cls.getClassLoader(), new Class[]{cls}, annotator);
    }

    @Override
    @SuppressWarnings({"squid:S3776", "squid:MethodCyclomaticComplexity"})
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if ("hashCode".equals(methodName) && method.getParameterCount() == 0) {
            if (hashCode == null)
                hashCode = hashCodeImpl();
            return hashCode;
        } else if ("equals".equals(methodName) && method.getParameterCount() == 1
                && method.getParameterTypes()[0].equals(Object.class)) {
            return equalsImpl(args[0]);
        } else if ("annotationType".equals(methodName) && method.getParameterCount() == 0) {
            return type;
        } else if ("toString".equals(methodName) && method.getParameterCount() == 0) {
            if (toString == null)
                toString = toStringImpl();
            return toString;
        } else {
            lastAccessed = method;
            Object value = values.get(method);
            if (value == null && method.getReturnType().isPrimitive()) {
                return Primitives.defaultValue(method.getReturnType());
            }
            return value;
        }
    }

    private  void copyFrom(T original) {
        if (original == null)
            return;
        Iterator> iterator = values.entrySet().iterator();
        while(iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            try {
                entry.setValue(entry.getKey().invoke(original));
            } catch (Exception e) {
                throw new SystemException(e);
            }
        }
        hashCode = null;
        toString = null;
    }

    @SuppressWarnings("unchecked")
    private int hashCodeImpl() {
        int hash = 0;
        Map.Entry entry;
        for(Iterator iterator = values.entrySet().iterator(); iterator.hasNext();
            hash += 127 * (entry.getKey().getName()).hashCode() ^ Primitives.hashCode(entry.getValue())) {
            entry = (Map.Entry) iterator.next();
        }
        return hash;
    }

    @SuppressWarnings("squid:S134")
    private boolean equalsImpl(Object object) {
        if (object == null)
            return false;
        if(object == this) {
            return true;
        } else if(!this.type.isInstance(object)) {
            return false;
        } else {
            Iterator> iterator = values.entrySet().iterator();
            while(iterator.hasNext()) {
                Map.Entry entry = iterator.next();
                try {
                    Object value2 = entry.getKey().invoke(object);
                    if (! Primitives.equals(entry.getValue(), value2))
                        return false;
                } catch (Exception e) {
                    Logger.suppress(e);
                    return false;
                }
            }
            return true;
        }
    }

    private String toStringImpl() {
        StringBuilder builder = new StringBuilder(128);
        builder.append('@');
        builder.append(type.getName());
        builder.append('(');
        boolean first = true;
        Iterator> iterator = values.entrySet().iterator();
        while(iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            if(first) {
                first = false;
            } else {
                builder.append(", ");
            }

            builder.append(entry.getKey().getName());
            builder.append('=');
            builder.append(Primitives.toString(entry.getValue()));
        }

        builder.append(')');
        return builder.toString();
    }

    public static class AnnotationValue {
        private Annotator handler;

        public AnnotationValue(Annotator handler) {
            this.handler = handler;
        }

        public  AnnotationValue set(Callable callable, T value) {
            return _set(callable, value);
        }

        @SuppressWarnings("squid:S00100")
        private  AnnotationValue _set(Callable callable, K value) {
            try {
                callable.call();
            } catch (Exception e) {
                throw new SystemException(e);
            }
            handler.values.put(handler.lastAccessed, value);
            handler.hashCode = null;
            handler.toString = null;
            handler.lastAccessed = null;
            return this;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy