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

phoswald.annotation.printer.AnnotationPrinter Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
package phoswald.annotation.printer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;

/**
 * Utility class for formatting annotations.
 */
public class AnnotationPrinter {

    /**
     * Formats the given annotation.
     *
     * @param annotation the annotation to be formatted, must not be null.
     * @return the annotation formatted using Java Syntax, never null or empty.
     */
    public String format(Annotation annotation) {
        StringBuilder sb = new StringBuilder();
        formatAnnotation(sb, annotation);
        return sb.toString();
    }

    private static void formatAnnotation(StringBuilder sb, Annotation annotation) {
        sb.append("@");
        sb.append(annotation.annotationType().getName().replace('$', '.'));
        Method[] methods = annotation.annotationType().getDeclaredMethods();
        Arrays.sort(methods, Comparator.comparing(Method::getName));
        int count = 0;
        for(Method method : methods) {
            Object value = getElement(annotation, method);
            if(value == null) {
                continue;
            }
            if(count == 0) {
                sb.append('(');
            } else {
                sb.append(", ");
            }
            if(!isSingleElement(methods)) {
                sb.append(method.getName()).append('=');
            }
            format(sb, value);
            count++;
        }
        if(count > 0) {
            sb.append(')');
        }
    }

    private static void formatArray(StringBuilder sb, Object array) {
        sb.append("{ ");
        int length = Array.getLength(array);
        for(int index = 0; index < length; index++) {
            Object element = Array.get(array, index);
            if(index > 0) {
                sb.append(", ");
            }
            format(sb, element);
        }
        if(length > 0) {
            sb.append(' ');
        }
        sb.append('}');
    }

    private static void formatClass(StringBuilder sb, Class value) {
        sb.append(value.getName() + ".class");
    }

    private static void formatEnum(StringBuilder sb, Enum value) {
        sb.append(value.getDeclaringClass().getName() + "." + value.name());
    }

    private static void format(StringBuilder sb, Object value) {
        if(value == null) {
            throw new IllegalArgumentException("Cannot handle null annotation element.");
        } else if(value instanceof Annotation) {
            formatAnnotation(sb, (Annotation) value);
        } else if(value.getClass().isArray()) {
            formatArray(sb, value);
        } else if(value instanceof Class) {
            formatClass(sb, (Class) value);
        } else if(value instanceof Enum) {
            formatEnum(sb, (Enum) value);
        } else if(value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Double) {
            sb.append(value);
        } else if(value instanceof Character) {
            sb.append('\'');
            appendChar(sb, (char) value);
            sb.append('\'');
        } else if(value instanceof Long) {
            sb.append(value + "L");
        } else if(value instanceof Float) {
            sb.append(value + "F");
        } else if(value instanceof String) {
            sb.append('"');
            for(char c : value.toString().toCharArray()) {
                appendChar(sb, c);
            }
            sb.append('"');
        } else {
            throw new IllegalArgumentException("Unsupported annotation element: " + value.getClass().getName());
        }
    }

    private static void appendChar(StringBuilder sb, char c) {
        switch(c) {
            case '\t':
                sb.append("\\t");
                break;
            case '\r':
                sb.append("\\r");
                break;
            case '\n':
                sb.append("\\n");
                break;
            case '\'':
            case '\"':
            case '\\':
                sb.append('\\').append(c);
                break;
            default:
                sb.append(c);
        }
    }

    private static Object getElement(Annotation annotation, Method method) {
        try {
            Object defaultValue = method.getDefaultValue();
            Object value = method.invoke(annotation);
            if(Objects.deepEquals(defaultValue, value)) {
                return null;
            }
            return value;
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException("Failed to inspect annotation.", e);
        }
    }

    private static boolean isSingleElement(Method[] methods) {
        return methods.length == 1 && methods[0].getName().equals("value");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy