@Override public Object handlePropertyAccess(Object self, ValueImpl impl, Object... args) { ValueDescriptorImpl<?> descriptor = impl.descriptor; boolean first = true; StringBuilder result = new StringBuilder(descriptor.getValueInterface().getName()); result.append('{'); for (PropertyImpl property : descriptor.internalGetProperties()) { Object selfValue = property.getGetHandler().handlePropertyAccess(self, impl); if (first) { first = false; } else { result.append("; "); } result.append(property.getName()); result.append(": "); if (property.getKind() == Kind.PRIMITIVE) { result.append(property.getParser().unparse(selfValue)); } else { result.append(selfValue); } } result.append('}'); return result.toString(); }
/** Completes the analysis of the {@link #getValueInterface()}. */ public void init() { Map<String, PropertyImpl> propertyByRawName = new HashMap<String, PropertyImpl>(); Map<Method, PropertyImpl> propertyByMethod = new HashMap<Method, PropertyImpl>(); for (Method method : valueInterface.getMethods()) { if (method.getDeclaringClass().isAssignableFrom(Value.class)) { // Ignore Value and Object type methods. continue; } int modifiers = method.getModifiers(); if (!Modifier.isPublic(modifiers)) { throw new AssertionError("Expected public modifier on '" + method + "'"); } if (Modifier.isStatic(modifiers)) { throw new AssertionError("No static methods allowed on '" + method + "'"); } if (method.getExceptionTypes().length > 0) { throw new AssertionError("Method must not declare exceptions: " + method); } boolean isGetter; String prefix; String methodName = method.getName(); if (methodName.startsWith("get")) { prefix = "get"; isGetter = true; } else if (methodName.startsWith("set")) { prefix = "set"; isGetter = false; } else if (methodName.startsWith("is")) { prefix = "is"; isGetter = true; } else if (methodName.startsWith("has")) { prefix = "has"; isGetter = true; } else if (methodName.startsWith("can")) { prefix = "can"; isGetter = true; } else if (methodName.startsWith("must")) { prefix = "must"; isGetter = true; } else { throw new AssertionError("Invalid method prefix: " + method); } Class<?> type; if (isGetter) { Class<?>[] types = method.getParameterTypes(); if (types.length != 0) { throw new AssertionError("Getter must not have parameters: " + method); } type = method.getReturnType(); if (type == Void.class || type == void.class) { throw new AssertionError("Getter must not have void return type: " + method); } boolean isBoolean = type == boolean.class || type == Boolean.class; if (!prefix.equals("get") && !isBoolean) { throw new AssertionError( "Non boolean getters must have '" + "get" + "' prefix: " + method); } } else { Class<?>[] types = method.getParameterTypes(); if (types.length != 1) { throw new AssertionError("Setter must have exactly one argument: " + method); } Class<?> returnType = method.getReturnType(); if (returnType != void.class) { throw new AssertionError("Setter must have void return type: " + method); } type = types[0]; } String postfix = methodName.substring(prefix.length()); if (Character.isLowerCase(postfix.charAt(0))) { throw new AssertionError("Expected upper case letter after method prefix: " + method); } String rawName = Character.toLowerCase(postfix.charAt(0)) + postfix.substring(1); PropertyImpl property = propertyByRawName.get(rawName); if (property == null) { int index = propertyByRawName.size(); property = new PropertyImpl(this, rawName, index); propertyByRawName.put(rawName, property); } if (isGetter) { property.initGetter(method); } propertyByMethod.put(method, property); } for (PropertyImpl property : propertyByRawName.values()) { PropertyImpl clash = properties.put(property.getName(), property); if (clash != null) { throw new IllegalArgumentException( "Properties must have unique names in interface '" + valueInterface.getName() + "': " + clash.getName()); } } for (Entry<Method, PropertyImpl> entry : propertyByMethod.entrySet()) { Method method = entry.getKey(); boolean isGetter = !method.getName().startsWith("set"); PropertyImpl property = entry.getValue(); handlerByMethod.put(method, isGetter ? property.getGetHandler() : property.getSetHandler()); } // Add object methods. handlerByMethod.put(EQUALS_METHOD, EQUALS_IMPL); handlerByMethod.put(HASH_CODE_METHOD, HASH_CODE_IMPL); handlerByMethod.put(TO_STRING_METHOD, TO_STRING_IMPL); // Add value interface methods. handlerByMethod.put(DESCRIPTOR_METHOD, DESCRIPTOR_IMPL); handlerByMethod.put(VALUE_METHOD, VALUE_IMPL); handlerByMethod.put(PUT_VALUE_METHOD, PUT_VALUE_IMPL); }