From 505226f8adb08820b938705b160ddf0e54ae0286 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 8 Apr 2013 17:57:56 +0200 Subject: [PATCH] Added the ability to match derived classes and interfaces. --- .../reflect/fuzzy/AbstractFuzzyMatcher.java | 19 +++ .../reflect/fuzzy/FuzzyClassContract.java | 129 +++++++++++++++--- 2 files changed, 127 insertions(+), 21 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/AbstractFuzzyMatcher.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/AbstractFuzzyMatcher.java index a93ea18f..0e522142 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/AbstractFuzzyMatcher.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/AbstractFuzzyMatcher.java @@ -62,6 +62,25 @@ public abstract class AbstractFuzzyMatcher implements Comparable obj) { diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/FuzzyClassContract.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/FuzzyClassContract.java index bb1bfcdb..3a15ab44 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/FuzzyClassContract.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/fuzzy/FuzzyClassContract.java @@ -1,6 +1,7 @@ package com.comphenix.protocol.reflect.fuzzy; import java.lang.reflect.Field; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -23,6 +24,9 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { private final ImmutableList> methodContracts; private final ImmutableList> constructorContracts; + private final ImmutableList>> baseclassContracts; + private final ImmutableList>> interfaceContracts; + /** * Represents a class contract builder. * @author Kristian @@ -33,6 +37,9 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { private List> methodContracts = Lists.newArrayList(); private List> constructorContracts = Lists.newArrayList(); + private List>> baseclassContracts = Lists.newArrayList(); + private List>> interfaceContracts = Lists.newArrayList(); + /** * Add a new field contract. * @param matcher - new field contract. @@ -89,18 +96,54 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { public Builder constructor(FuzzyMethodContract.Builder builder) { return constructor(builder.build()); } + + /** + * Add a new base class contract. + * @param matcher - new base class contract. + * @return This builder, for chaining. + */ + public Builder baseclass(AbstractFuzzyMatcher> matcher) { + baseclassContracts.add(matcher); + return this; + } + + /** + * Add a new base class contract. + * @param matcher - builder for the new base class contract. + * @return This builder, for chaining. + */ + public Builder baseclass(FuzzyClassContract.Builder builder) { + return baseclass(builder.build()); + } + + /** + * Add a new interface contract. + * @param matcher - new interface contract. + * @return This builder, for chaining. + */ + public Builder interfaces(AbstractFuzzyMatcher> matcher) { + interfaceContracts.add(matcher); + return this; + } + + /** + * Add a new interface contract. + * @param matcher - builder for the new interface contract. + * @return This builder, for chaining. + */ + public Builder interfaces(FuzzyClassContract.Builder builder) { + return interfaces(builder.build()); + } public FuzzyClassContract build() { Collections.sort(fieldContracts); Collections.sort(methodContracts); Collections.sort(constructorContracts); + Collections.sort(baseclassContracts); + Collections.sort(interfaceContracts); // Construct a new class matcher - return new FuzzyClassContract( - ImmutableList.copyOf(fieldContracts), - ImmutableList.copyOf(methodContracts), - ImmutableList.copyOf(constructorContracts) - ); + return new FuzzyClassContract(this); } } @@ -114,17 +157,15 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { /** * Constructs a new fuzzy class contract with the given contracts. - * @param fieldContracts - field contracts. - * @param methodContracts - method contracts. - * @param constructorContracts - constructor contracts. + * @param builder - the builder that is constructing us. */ - private FuzzyClassContract(ImmutableList> fieldContracts, - ImmutableList> methodContracts, - ImmutableList> constructorContracts) { + private FuzzyClassContract(Builder builder) { super(); - this.fieldContracts = fieldContracts; - this.methodContracts = methodContracts; - this.constructorContracts = constructorContracts; + this.fieldContracts = ImmutableList.copyOf(builder.fieldContracts); + this.methodContracts = ImmutableList.copyOf(builder.methodContracts); + this.constructorContracts = ImmutableList.copyOf(builder.constructorContracts); + this.baseclassContracts = ImmutableList.copyOf(builder.baseclassContracts); + this.interfaceContracts = ImmutableList.copyOf(builder.interfaceContracts); } /** @@ -157,12 +198,34 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { return constructorContracts; } + /** + * Retrieve an immutable list of every baseclass contract. + *

+ * This list is ordered in descending order of priority. + * @return List of every baseclass contract. + */ + public ImmutableList>> getBaseclassContracts() { + return baseclassContracts; + } + + /** + * Retrieve an immutable list of every interface contract. + *

+ * This list is ordered in descending order of priority. + * @return List of every interface contract. + */ + public ImmutableList>> getInterfaceContracts() { + return interfaceContracts; + } + @Override protected int calculateRoundNumber() { // Find the highest round number return combineRounds(findHighestRound(fieldContracts), - combineRounds(findHighestRound(methodContracts), - findHighestRound(constructorContracts))); + findHighestRound(methodContracts), + findHighestRound(constructorContracts), + findHighestRound(interfaceContracts), + findHighestRound(baseclassContracts)); } private int findHighestRound(Collection> list) { @@ -179,12 +242,19 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { FuzzyReflection reflection = FuzzyReflection.fromClass(value, true); // Make sure all the contracts are valid - return processContracts(reflection.getFields(), value, fieldContracts) && - processContracts(MethodInfo.fromMethods(reflection.getMethods()), value, methodContracts) && - processContracts(MethodInfo.fromConstructors(value.getDeclaredConstructors()), value, constructorContracts); + return (fieldContracts.size() == 0 || + processContracts(reflection.getFields(), value, fieldContracts)) && + (methodContracts.size() == 0 || + processContracts(MethodInfo.fromMethods(reflection.getMethods()), value, methodContracts)) && + (constructorContracts.size() == 0 || + processContracts(MethodInfo.fromConstructors(value.getDeclaredConstructors()), value, constructorContracts)) && + (baseclassContracts.size() == 0 || + processValue(value.getSuperclass(), parent, baseclassContracts)) && + (interfaceContracts.size() == 0 || + processContracts(Arrays.asList(value.getInterfaces()), (Class) parent, interfaceContracts)); } - private boolean processContracts(Collection values, Class parent, List> matchers) { + private boolean processContracts(Collection values, Object parent, List> matchers) { boolean[] accepted = new boolean[matchers.size()]; int count = accepted.length; @@ -205,7 +275,18 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { return count == 0; } - private int processValue(T value, Class parent, boolean accepted[], List> matchers) { + private boolean processValue(T value, Object parent, List> matchers) { + for (int i = 0; i < matchers.size(); i++) { + if (matchers.get(i).isMatch(value, parent)) { + return true; + } + } + + // No match + return false; + } + + private int processValue(T value, Object parent, boolean accepted[], List> matchers) { // The order matters for (int i = 0; i < matchers.size(); i++) { if (!accepted[i]) { @@ -235,6 +316,12 @@ public class FuzzyClassContract extends AbstractFuzzyMatcher> { if (constructorContracts.size() > 0) { params.put("constructors", constructorContracts); } + if (baseclassContracts.size() > 0) { + params.put("baseclasses", baseclassContracts); + } + if (interfaceContracts.size() > 0) { + params.put("interfaces", interfaceContracts); + } return "{\n " + Joiner.on(", \n ").join(params.entrySet()) + "\n}"; } }