All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.e6tech.elements.common.reflection.Annotator Maven / Gradle / Ivy
/*
* 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 extends Annotation> 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 extends Annotation> cls, BiConsumer consumer) {
return create(cls, null, consumer);
}
@SuppressWarnings("unchecked")
public static T create(Class extends Annotation> 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;
}
}
}