public static int scoreInterface(final MetaClass parm, final MetaClass arg) { if (parm.isInterface()) { final MetaClass[] iface = arg.getInterfaces(); if (iface != null) { for (final MetaClass c : iface) { if (c == parm) return 1; else if (parm.isAssignableFrom(c)) return scoreInterface(parm, arg.getSuperClass()); } } } return 0; }
public static MetaMethod getBestCandidate( final MetaClass[] arguments, final String method, final MetaClass decl, MetaMethod[] methods, final boolean classTarget) { if (methods == null || methods.length == 0) { return null; } MetaParameter[] parmTypes; MetaMethod bestCandidate = null; int bestScore = 0; int score; boolean retry = false; do { for (final MetaMethod meth : methods) { if (classTarget && (meth.isStatic())) continue; if (method.equals(meth.getName())) { final boolean isVarArgs = meth.isVarArgs(); if ((parmTypes = meth.getParameters()).length != arguments.length && !isVarArgs) { continue; } else if (arguments.length == 0 && parmTypes.length == 0) { bestCandidate = meth; break; } score = scoreMethods(arguments, parmTypes, isVarArgs); if (score != 0 && score > bestScore) { bestCandidate = meth; bestScore = score; } } } if (!retry && bestCandidate == null && decl.isInterface()) { final MetaMethod[] objMethods = Object_MetaClass.getMethods(); final MetaMethod[] nMethods = new MetaMethod[methods.length + objMethods.length]; System.arraycopy(methods, 0, nMethods, 0, methods.length); System.arraycopy(objMethods, 0, nMethods, methods.length, objMethods.length); methods = nMethods; retry = true; } else { break; } } while (true); return bestCandidate; }
BuildMetaClass make(final String proxyClassName, final MetaClass toProxy, final String privateAccessorType) { final ClassStructureBuilder builder; final boolean renderEqualsAndHash; if (!toProxy.isInterface()) { renderEqualsAndHash = true; if (toProxy.isFinal()) { throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName() + " is an unproxiable class because it is final"); } if (!toProxy.isDefaultInstantiable()) { throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName() + " must have a default " + "no-arg constructor"); } builder = ClassBuilder.define(proxyClassName, toProxy).publicScope().body(); } else { renderEqualsAndHash = false; builder = ClassBuilder.define(proxyClassName).publicScope().implementsInterface(toProxy).body(); } final String proxyVar = "$$_proxy_$$"; final Set<String> renderedMethods = new HashSet<String>(); final Map<String, MetaType> typeVariableMap = new HashMap<String, MetaType>(); final MetaParameterizedType metaParameterizedType = toProxy.getParameterizedType(); if (metaParameterizedType != null) { int i = 0; for (final MetaTypeVariable metaTypeVariable : toProxy.getTypeParameters()) { typeVariableMap.put(metaTypeVariable.getName(), metaParameterizedType.getTypeParameters()[i++]); } } builder.privateField(proxyVar, toProxy).finish(); final Set<Map.Entry<String, ProxyProperty>> entries = proxyProperties.entrySet(); for (final Map.Entry<String, ProxyProperty> entry : entries) { builder.privateField(entry.getValue().getEncodedProperty(), entry.getValue().getType()).finish(); builder.packageMethod(void.class, "$set_" + entry.getKey(), Parameter.of(entry.getValue().getType(), "o")) .append(Stmt.loadVariable(entry.getValue().getEncodedProperty()).assignValue(Refs.get("o"))) .finish(); } for (final MetaMethod method : toProxy.getMethods()) { final String methodString = GenUtil.getMethodString(method); if (renderedMethods.contains(methodString) || method.getName().equals("hashCode") || (method.getName().equals("equals") && method.getParameters().length == 1 && method.getParameters()[0].getType().getFullyQualifiedName().equals(Object.class.getName()))) continue; renderedMethods.add(methodString); if ((!method.isPublic() && !method.isProtected()) || method.isSynthetic() || method.isFinal() || method.isStatic() || method.getDeclaringClass().getFullyQualifiedName().equals(Object.class.getName())) continue; final List<Parameter> methodParms = new ArrayList<Parameter>(); final MetaParameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { methodParms.add(Parameter.of(parameters[i].getType().getErased(), "a" + i)); } final DefParameters defParameters = DefParameters.fromParameters(methodParms); final BlockBuilder methBody = builder.publicMethod(method.getReturnType(), method.getName()) .annotatedWith(OVERRIDE_ANNOTATION) .parameters(defParameters) .throws_(method.getCheckedExceptions()); methBody.appendAll(getAroundInvokeStatements(method)); methBody.appendAll(getBeforeStatements(method)); final List<Parameter> parms = defParameters.getParameters(); final Statement[] statementVars = new Statement[parms.size()]; for (int i = 0; i < parms.size(); i++) { statementVars[i] = loadVariable(parms.get(i).getName()); } if (!method.isPublic()) { PrivateAccessUtil.addPrivateAccessStubs(privateAccessorType, builder, method, new Modifier[0]); final Statement[] privateAccessStmts = new Statement[statementVars.length + 1]; privateAccessStmts[0] = Refs.get(proxyVar); System.arraycopy(statementVars, 0, privateAccessStmts, 1, statementVars.length); if (method.getReturnType().isVoid()) { methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts)); } else { methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts).returnValue()); } } else { if (method.getReturnType().isVoid()) { methBody._(loadVariable(proxyVar).invoke(method, statementVars)); } else { methBody._(loadVariable(proxyVar).invoke(method, statementVars).returnValue()); } } methBody.appendAll(getAfterStatements(method)); methBody.appendAll(getAroundInvokeStatements(method)); methBody.finish(); } if (renderEqualsAndHash) { // implement hashCode() builder.publicMethod(int.class, "hashCode") .annotatedWith(OVERRIDE_ANNOTATION) .body() ._( If.isNull(loadVariable(proxyVar)) ._(throw_(IllegalStateException.class, "call to hashCode() on an unclosed proxy.")) .finish() .else_() ._(Stmt.loadVariable(proxyVar).invoke("hashCode").returnValue()) .finish() ) .finish(); // implements equals() builder.publicMethod(boolean.class, "equals", Parameter.of(Object.class, "o")) .annotatedWith(OVERRIDE_ANNOTATION) .body() ._( If.isNull(loadVariable(proxyVar)) ._(throw_(IllegalStateException.class, "call to equals() on an unclosed proxy.")) .finish() .else_() ._(Stmt.loadVariable(proxyVar).invoke("equals", Refs.get("o")).returnValue()) .finish() ) .finish(); } builder.publicMethod(void.class, PROXY_BIND_METHOD).parameters(DefParameters.of(Parameter.of(toProxy, "proxy"))) ._(loadVariable(proxyVar).assignValue(loadVariable("proxy"))).finish(); return builder.getClassDefinition(); }