Add an equality and hashCode() method to all the matchers.
Dieser Commit ist enthalten in:
Ursprung
75f05732bb
Commit
eaf7ea9618
@ -6,6 +6,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,7 +21,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
|||||||
protected int modifiersBanned;
|
protected int modifiersBanned;
|
||||||
|
|
||||||
protected Pattern nameRegex;
|
protected Pattern nameRegex;
|
||||||
protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ExactClassMatcher.MATCH_ALL;
|
protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ClassExactMatcher.MATCH_ALL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this contract can be modified.
|
* Whether or not this contract can be modified.
|
||||||
@ -256,7 +257,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
|||||||
if (nameRegex != null) {
|
if (nameRegex != null) {
|
||||||
map.put("name", nameRegex.pattern());
|
map.put("name", nameRegex.pattern());
|
||||||
}
|
}
|
||||||
if (declaringMatcher != ExactClassMatcher.MATCH_ALL) {
|
if (declaringMatcher != ClassExactMatcher.MATCH_ALL) {
|
||||||
map.put("declaring", declaringMatcher);
|
map.put("declaring", declaringMatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,4 +272,27 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
|
|||||||
int snipped = value & ((1 << bits) - 1);
|
int snipped = value & ((1 << bits) - 1);
|
||||||
return Integer.toBinaryString(snipped);
|
return Integer.toBinaryString(snipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// Immutablity is awesome
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof AbstractFuzzyMember) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
AbstractFuzzyMember<T> other = (AbstractFuzzyMember<T>) obj;
|
||||||
|
|
||||||
|
return modifiersBanned == other.modifiersBanned &&
|
||||||
|
modifiersRequired == other.modifiersRequired &&
|
||||||
|
FuzzyMatchers.checkPattern(nameRegex, other.nameRegex) &&
|
||||||
|
Objects.equal(declaringMatcher, other.declaringMatcher);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(modifiersBanned, modifiersRequired,
|
||||||
|
nameRegex != null ? nameRegex.pattern() : null, declaringMatcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package com.comphenix.protocol.reflect.fuzzy;
|
package com.comphenix.protocol.reflect.fuzzy;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to check class equality.
|
* Used to check class equality.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
class ClassExactMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
||||||
/**
|
/**
|
||||||
* Different matching rules.
|
* Different matching rules.
|
||||||
*/
|
*/
|
||||||
@ -29,7 +31,7 @@ class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
|||||||
/**
|
/**
|
||||||
* Match any class.
|
* Match any class.
|
||||||
*/
|
*/
|
||||||
public static final ExactClassMatcher MATCH_ALL = new ExactClassMatcher(null, Options.MATCH_SUPER);
|
public static final ClassExactMatcher MATCH_ALL = new ClassExactMatcher(null, Options.MATCH_SUPER);
|
||||||
|
|
||||||
private final Class<?> matcher;
|
private final Class<?> matcher;
|
||||||
private final Options option;
|
private final Options option;
|
||||||
@ -39,7 +41,7 @@ class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
|||||||
* @param matcher - the matching class, or NULL to represent anything.
|
* @param matcher - the matching class, or NULL to represent anything.
|
||||||
* @param option - options specifying the matching rules.
|
* @param option - options specifying the matching rules.
|
||||||
*/
|
*/
|
||||||
ExactClassMatcher(Class<?> matcher, Options option) {
|
ClassExactMatcher(Class<?> matcher, Options option) {
|
||||||
this.matcher = matcher;
|
this.matcher = matcher;
|
||||||
this.option = option;
|
this.option = option;
|
||||||
}
|
}
|
||||||
@ -116,4 +118,22 @@ class ExactClassMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
|||||||
else
|
else
|
||||||
return "Exact " + matcher;
|
return "Exact " + matcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(matcher, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof ClassExactMatcher) {
|
||||||
|
ClassExactMatcher other = (ClassExactMatcher) obj;
|
||||||
|
|
||||||
|
return Objects.equal(matcher, other.matcher) &&
|
||||||
|
Objects.equal(option, other.option);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.comphenix.protocol.reflect.fuzzy;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a class matches based on its name using a regular expression.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
class ClassRegexMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
||||||
|
private final Pattern regex;
|
||||||
|
private final int priority;
|
||||||
|
|
||||||
|
public ClassRegexMatcher(Pattern regex, int priority) {
|
||||||
|
if (regex == null)
|
||||||
|
throw new IllegalArgumentException("Regular expression pattern cannot be NULL.");
|
||||||
|
this.regex = regex;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMatch(Class<?> value, Object parent) {
|
||||||
|
if (value != null)
|
||||||
|
return regex.matcher(value.getCanonicalName()).matches();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int calculateRoundNumber() {
|
||||||
|
return -priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "class name of " + regex.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(regex, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof ClassRegexMatcher) {
|
||||||
|
ClassRegexMatcher other = (ClassRegexMatcher) obj;
|
||||||
|
|
||||||
|
return priority == other.priority &&
|
||||||
|
FuzzyMatchers.checkPattern(regex, other.regex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.comphenix.protocol.reflect.fuzzy;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a class matcher that checks for equality using a given set of classes.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
class ClassSetMatcher extends AbstractFuzzyMatcher<Class<?>> {
|
||||||
|
private final Set<Class<?>> classes;
|
||||||
|
|
||||||
|
public ClassSetMatcher(Set<Class<?>> classes) {
|
||||||
|
if (classes == null)
|
||||||
|
throw new IllegalArgumentException("Set of classes cannot be NULL.");
|
||||||
|
this.classes = classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMatch(Class<?> value, Object parent) {
|
||||||
|
return classes.contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int calculateRoundNumber() {
|
||||||
|
int roundNumber = 0;
|
||||||
|
|
||||||
|
// The highest round number (except zero).
|
||||||
|
for (Class<?> clazz : classes) {
|
||||||
|
roundNumber = combineRounds(roundNumber, -ClassExactMatcher.getClassNumber(clazz));
|
||||||
|
}
|
||||||
|
return roundNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "match any: " + classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return classes.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof ClassSetMatcher) {
|
||||||
|
// See if the sets are equal
|
||||||
|
return Objects.equal(classes, ((ClassSetMatcher) obj).classes);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -6,13 +6,15 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a field matcher.
|
* Represents a field matcher.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
||||||
private AbstractFuzzyMatcher<Class<?>> typeMatcher = ExactClassMatcher.MATCH_ALL;
|
private AbstractFuzzyMatcher<Class<?>> typeMatcher = ClassExactMatcher.MATCH_ALL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a builder for a field matcher.
|
* Represents a builder for a field matcher.
|
||||||
@ -156,9 +158,25 @@ public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
|||||||
protected Map<String, Object> getKeyValueView() {
|
protected Map<String, Object> getKeyValueView() {
|
||||||
Map<String, Object> member = super.getKeyValueView();
|
Map<String, Object> member = super.getKeyValueView();
|
||||||
|
|
||||||
if (typeMatcher != ExactClassMatcher.MATCH_ALL) {
|
if (typeMatcher != ClassExactMatcher.MATCH_ALL) {
|
||||||
member.put("type", typeMatcher);
|
member.put("type", typeMatcher);
|
||||||
}
|
}
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(typeMatcher, super.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// Use the member equals method
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof FuzzyFieldContract && super.equals(obj)) {
|
||||||
|
return Objects.equal(typeMatcher, ((FuzzyFieldContract) obj).typeMatcher);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.lang.reflect.Member;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,7 +22,7 @@ public class FuzzyMatchers {
|
|||||||
* @return A new class mathcher.
|
* @return A new class mathcher.
|
||||||
*/
|
*/
|
||||||
public static AbstractFuzzyMatcher<Class<?>> matchExact(Class<?> matcher) {
|
public static AbstractFuzzyMatcher<Class<?>> matchExact(Class<?> matcher) {
|
||||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_EXACT);
|
return new ClassExactMatcher(matcher, ClassExactMatcher.Options.MATCH_EXACT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,29 +39,8 @@ public class FuzzyMatchers {
|
|||||||
* @param classes - set of classes to match.
|
* @param classes - set of classes to match.
|
||||||
* @return A new class mathcher.
|
* @return A new class mathcher.
|
||||||
*/
|
*/
|
||||||
public static AbstractFuzzyMatcher<Class<?>> matchAnyOf(final Set<Class<?>> classes) {
|
public static AbstractFuzzyMatcher<Class<?>> matchAnyOf(Set<Class<?>> classes) {
|
||||||
return new AbstractFuzzyMatcher<Class<?>>() {
|
return new ClassSetMatcher(classes);
|
||||||
@Override
|
|
||||||
public boolean isMatch(Class<?> value, Object parent) {
|
|
||||||
return classes.contains(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int calculateRoundNumber() {
|
|
||||||
int roundNumber = 0;
|
|
||||||
|
|
||||||
// The highest round number (except zero).
|
|
||||||
for (Class<?> clazz : classes) {
|
|
||||||
roundNumber = combineRounds(roundNumber, -ExactClassMatcher.getClassNumber(clazz));
|
|
||||||
}
|
|
||||||
return roundNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("match any: %s", Joiner.on(",").join(classes));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,7 +49,7 @@ public class FuzzyMatchers {
|
|||||||
* @return A new class mathcher.
|
* @return A new class mathcher.
|
||||||
*/
|
*/
|
||||||
public static AbstractFuzzyMatcher<Class<?>> matchSuper(Class<?> matcher) {
|
public static AbstractFuzzyMatcher<Class<?>> matchSuper(Class<?> matcher) {
|
||||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_SUPER);
|
return new ClassExactMatcher(matcher, ClassExactMatcher.Options.MATCH_SUPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,7 +58,7 @@ public class FuzzyMatchers {
|
|||||||
* @return A new class mathcher.
|
* @return A new class mathcher.
|
||||||
*/
|
*/
|
||||||
public static AbstractFuzzyMatcher<Class<?>> matchDerived(Class<?> matcher) {
|
public static AbstractFuzzyMatcher<Class<?>> matchDerived(Class<?> matcher) {
|
||||||
return new ExactClassMatcher(matcher, ExactClassMatcher.Options.MATCH_DERIVED);
|
return new ClassExactMatcher(matcher, ClassExactMatcher.Options.MATCH_DERIVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,25 +68,7 @@ public class FuzzyMatchers {
|
|||||||
* @return A fuzzy class matcher based on name.
|
* @return A fuzzy class matcher based on name.
|
||||||
*/
|
*/
|
||||||
public static AbstractFuzzyMatcher<Class<?>> matchRegex(final Pattern regex, final int priority) {
|
public static AbstractFuzzyMatcher<Class<?>> matchRegex(final Pattern regex, final int priority) {
|
||||||
return new AbstractFuzzyMatcher<Class<?>>() {
|
return new ClassRegexMatcher(regex, priority);
|
||||||
@Override
|
|
||||||
public boolean isMatch(Class<?> value, Object parent) {
|
|
||||||
if (value != null)
|
|
||||||
return regex.matcher(value.getCanonicalName()).matches();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int calculateRoundNumber() {
|
|
||||||
return -priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "class name of " + regex.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +109,34 @@ public class FuzzyMatchers {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "match parent class";
|
return "match parent class";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// If they're the same type, then yes
|
||||||
|
return obj != null && obj.getClass() == this.getClass();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if two patterns are the same.
|
||||||
|
* <p>
|
||||||
|
* Note that two patterns may be functionally the same, but nevertheless be different.
|
||||||
|
* @param a - the first pattern.
|
||||||
|
* @param b - the second pattern.
|
||||||
|
* @return TRUE if they are compiled from the same pattern, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
static boolean checkPattern(Pattern a, Pattern b) {
|
||||||
|
if (a == null)
|
||||||
|
return b == null;
|
||||||
|
else if (b == null)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return a.pattern().equals(b.pattern());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import javax.annotation.Nonnull;
|
|||||||
import org.apache.commons.lang.NotImplementedException;
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.MethodInfo;
|
import com.comphenix.protocol.reflect.MethodInfo;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Match return value
|
// Match return value
|
||||||
private AbstractFuzzyMatcher<Class<?>> returnMatcher = ExactClassMatcher.MATCH_ALL;
|
private AbstractFuzzyMatcher<Class<?>> returnMatcher = ClassExactMatcher.MATCH_ALL;
|
||||||
|
|
||||||
// Handle parameters and exceptions
|
// Handle parameters and exceptions
|
||||||
private List<ParameterClassMatcher> paramMatchers;
|
private List<ParameterClassMatcher> paramMatchers;
|
||||||
@ -500,7 +501,7 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
|||||||
Map<String, Object> member = super.getKeyValueView();
|
Map<String, Object> member = super.getKeyValueView();
|
||||||
|
|
||||||
// Only add fields that are actual contraints
|
// Only add fields that are actual contraints
|
||||||
if (returnMatcher != ExactClassMatcher.MATCH_ALL) {
|
if (returnMatcher != ClassExactMatcher.MATCH_ALL) {
|
||||||
member.put("return", returnMatcher);
|
member.put("return", returnMatcher);
|
||||||
}
|
}
|
||||||
if (paramMatchers.size() > 0) {
|
if (paramMatchers.size() > 0) {
|
||||||
@ -514,4 +515,25 @@ public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
|||||||
}
|
}
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(returnMatcher, paramMatchers, exceptionMatchers, paramCount, super.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// Use the member equals method
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (obj instanceof FuzzyMethodContract && super.equals(obj)) {
|
||||||
|
FuzzyMethodContract other = (FuzzyMethodContract) obj;
|
||||||
|
|
||||||
|
return Objects.equal(paramCount, other.paramCount) &&
|
||||||
|
Objects.equal(returnMatcher, other.returnMatcher) &&
|
||||||
|
Objects.equal(paramMatchers, other.paramMatchers) &&
|
||||||
|
Objects.equal(exceptionMatchers, other.exceptionMatchers);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren