/** * Copyright (C) 2009-2011 the original author or authors. * See the notice.md file distributed with this work for additional * information regarding copyright ownership. * * 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 org.fusesource.restygwt.rebind.util; import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Method; /** * An utility class that gets a String representation of an annotation. * * @author <a href="mailto:bogdan.mustiata@gmail.com">Bogdan Mustiata</a> */ public class AnnotationCopyUtil { public static String getAnnotationAsString(Annotation annotation) { StringBuilder result = encodeAnnotationName(annotation); if (hasAnnotationAttributes(annotation)) { encodeAnnotationAttributes(annotation, result); } return result.toString(); } private static StringBuilder encodeAnnotationName(Annotation annotation) { return new StringBuilder( "@" ) .append(annotation.annotationType().getCanonicalName()); } private static boolean hasAnnotationAttributes(Annotation annotation) { return annotation.annotationType().getDeclaredMethods().length != 0; } private static void encodeAnnotationAttributes(Annotation annotation, StringBuilder result) { result.append("("); OnceFirstIterator<String> comma = new OnceFirstIterator<String>("", ", "); for (Method method : annotation.annotationType().getDeclaredMethods()) { Object value = readAnnotationAttribute(annotation, method); String encodedValue = encodeAnnotationValue(value); // Strip regex expressions from Path annotation value if (javax.ws.rs.Path.class == annotation.annotationType()) { encodedValue = encodedValue.replaceAll("\\{\\s*(\\S+)\\s*:\\s*[^{}]+\\}", "{$1}"); } if(encodedValue != null) { result.append( comma.next() ) .append( method.getName() ) .append( " = " ) .append( encodedValue ); } } result.append(")"); } private static Object readAnnotationAttribute(Annotation annotation, Method annotationAttribute) { try { return annotationAttribute.invoke(annotation); } catch (Exception e) { throw new IllegalArgumentException("Unable to read attribute " + annotationAttribute + " from " + annotation, e); } } /** * Returns the string representation of {@code value} or {@code null}, if the element should not be added. * * @param value * @return * @throws IllegalArgumentException Wrong value type */ private static String encodeAnnotationValue(Object value) { // Values of annotation elements must not be "null" if(null != value) { if (value instanceof String) { return readStringValue(value); } else if (value instanceof Number) { return readNumberValue(value); } else if (value.getClass().isArray()) { // workaround for ClassCastException: [Ljava.lang.Object; cannot be cast to [I // ignore empty arrays, because it becomes Object[] if(Array.getLength(value) > 0) { return readArrayValue(value); } return null; } else if (value instanceof Annotation) { return getAnnotationAsString((Annotation) value); } else if (value instanceof Boolean) { return readBooleanValue((Boolean) value); } else if (value instanceof Class) { return readClassValue((Class) value); } } throw new IllegalArgumentException("Unsupported value for encodeAnnotationValue: " + value); } private static String readBooleanValue(Boolean value) { return Boolean.toString(value); } private static String readArrayValue(Object value) { StringBuilder result = new StringBuilder(); OnceFirstIterator<String> comma = new OnceFirstIterator<String>("", ", "); result.append("{"); for (int i = 0; i < Array.getLength(value); i++) { Object arrayValue = Array.get(value, i); result.append(comma.next()) .append(encodeAnnotationValue(arrayValue)); } result.append("}"); return result.toString(); } private static String readNumberValue(Object value) { return value.toString(); } private static String readStringValue(Object value) { return "\"" + value.toString().replace("\"", "\\\"").replace("\n", "\\n") + "\""; } private static String readClassValue(Class value) { return value.getCanonicalName() + ".class"; } }