Skip to content

Commit ee538c0

Browse files
Adjusted API per suggestions from @sf105
Removed the utils class, and renamed package to more-general "reflection" rather than the "visibility" moniker that's specific to this small feature.
1 parent 96972e3 commit ee538c0

File tree

13 files changed

+224
-131
lines changed

13 files changed

+224
-131
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.hamcrest.reflection;
2+
3+
import java.lang.reflect.Member;
4+
import java.lang.reflect.Modifier;
5+
import java.util.Objects;
6+
7+
public enum Visibility
8+
{
9+
PUBLIC("public"),
10+
PROTECTED("protected"),
11+
PACKAGE_PROTECTED("package-protected (no modifiers)"),
12+
PRIVATE("private");
13+
14+
public String getDescription()
15+
{
16+
return description;
17+
}
18+
19+
private final String description;
20+
21+
Visibility(String description)
22+
{
23+
this.description = description;
24+
}
25+
26+
static Visibility of(Class<?> clazz)
27+
{
28+
Objects.requireNonNull(clazz, "Cannot determine the visibility of a null-valued reflective Class object");
29+
30+
if (Modifier.isPublic(clazz.getModifiers()))
31+
{
32+
return Visibility.PUBLIC;
33+
}
34+
if (Modifier.isProtected(clazz.getModifiers()))
35+
{
36+
return Visibility.PROTECTED;
37+
}
38+
if (Modifier.isPrivate(clazz.getModifiers()))
39+
{
40+
return Visibility.PRIVATE;
41+
}
42+
return Visibility.PACKAGE_PROTECTED;
43+
}
44+
45+
static Visibility of(Member member)
46+
{
47+
Objects.requireNonNull(member, "Cannot determine the visibility of a null-valued reflective member object");
48+
49+
if (Modifier.isPublic(member.getModifiers()))
50+
{
51+
return Visibility.PUBLIC;
52+
}
53+
if (Modifier.isProtected(member.getModifiers()))
54+
{
55+
return Visibility.PROTECTED;
56+
}
57+
if (Modifier.isPrivate(member.getModifiers()))
58+
{
59+
return Visibility.PRIVATE;
60+
}
61+
return Visibility.PACKAGE_PROTECTED;
62+
}
63+
}

hamcrest/src/main/java/org/hamcrest/visibility/VisibilityMatcher.java renamed to hamcrest/src/main/java/org/hamcrest/reflection/VisibilityMatcher.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.hamcrest.visibility;
1+
package org.hamcrest.reflection;
22

33
import org.hamcrest.BaseMatcher;
44
import org.hamcrest.Description;
@@ -8,8 +8,12 @@
88
/**
99
* Matches the visibility of a reflective element, like a {@link Class} or a {@link java.lang.reflect.Method},
1010
* to make assertions about the scope of a module's API.
11+
* <p>
12+
* This class is intentionally not exposed to the public API, to help keep implementation details hidden (and easy to change).
13+
* Please use {@link VisibilityMatchers} to instantiate instances of this class.
1114
*
12-
* @param <T> the type of the element being matched; could be anything
15+
* @param <T>
16+
* the type of the element being matched; could be anything
1317
* @see VisibilityMatchers
1418
*/
1519
class VisibilityMatcher<T> extends BaseMatcher<T>
@@ -30,11 +34,11 @@ public boolean matches(Object actual)
3034
}
3135
if (actual instanceof Class)
3236
{
33-
return expectedVisibility == VisibilityUtils.getVisibility((Class<?>) actual);
37+
return expectedVisibility == Visibility.of((Class<?>) actual);
3438
}
3539
if (actual instanceof Member)
3640
{
37-
return expectedVisibility == VisibilityUtils.getVisibility((Member) actual);
41+
return expectedVisibility == Visibility.of((Member) actual);
3842
}
3943
return false;
4044
}
@@ -53,13 +57,13 @@ public boolean matches(Object actual)
5357
else if (item instanceof Class)
5458
{
5559
description.appendText("was a ")
56-
.appendText(VisibilityUtils.getVisibility((Class<?>) item).getDescription())
60+
.appendText(Visibility.of((Class<?>) item).getDescription())
5761
.appendText(" class");
5862
}
5963
else if (item instanceof Member)
6064
{
6165
description.appendText("was a ")
62-
.appendText(VisibilityUtils.getVisibility((Member) item).getDescription())
66+
.appendText(Visibility.of((Member) item).getDescription())
6367
.appendText(" ")
6468
.appendText(item.getClass().getName());
6569
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package org.hamcrest.reflection;
2+
3+
import org.hamcrest.Matcher;
4+
5+
/**
6+
* Defines matchers that check the visibility of reflective objects like {@link java.lang.Class} or {@link java.lang.reflect.Method}.
7+
* {@code null} values never match, nor do normal objects; these simply do not match, without raising an Exception.
8+
*/
9+
public class VisibilityMatchers
10+
{
11+
// Each matcher is stateless and can match any type, so the individual instances are only made once and stored here for re-use.
12+
private static final VisibilityMatcher<?> PUBLIC = new VisibilityMatcher<>(Visibility.PUBLIC);
13+
private static final VisibilityMatcher<?> PROTECTED = new VisibilityMatcher<>(Visibility.PROTECTED);
14+
private static final VisibilityMatcher<?> PACKAGE_PROTECTED = new VisibilityMatcher<>(Visibility.PACKAGE_PROTECTED);
15+
private static final VisibilityMatcher<?> PRIVATE = new VisibilityMatcher<>(Visibility.PRIVATE);
16+
17+
/**
18+
* Matchers reflective elements that have public visibility.
19+
* Specifically, this matcher only matches elements marked with the keyword {@code public}.
20+
* <br>
21+
* This method matches {@link Class} objects or other {@link java.lang.reflect.Member reflective objects}
22+
* like {@link java.lang.reflect.Field} or {@link java.lang.reflect.Method} used in reflection.
23+
* Any other kind of object, or {@code null} values, do not match (but will not cause an Exception).
24+
*
25+
* @param <T>
26+
* the type of the object being matched
27+
* @return a matcher that matches reflective elements with exactly the given level of visibility
28+
*/
29+
@SuppressWarnings("unchecked")
30+
public static <T> Matcher<T> isPublic()
31+
{
32+
// Each matcher is stateless and can match any type (the generic <T> is for type safety at the use site),
33+
// so it's fine to cast the non-reifiable generic type here at runtime and re-use the same instance.
34+
return (Matcher<T>) PUBLIC;
35+
}
36+
37+
/**
38+
* Matchers reflective elements that have protected visibility.
39+
* Specifically, this matcher only matches elements marked with the keyword {@code protected}; it does NOT match public or private elements.
40+
* <br>
41+
* This method matches {@link Class} objects or other {@link java.lang.reflect.Member reflective objects}
42+
* like {@link java.lang.reflect.Field} or {@link java.lang.reflect.Method} used in reflection.
43+
* Any other kind of object, or {@code null} values, do not match (but will not cause an Exception).
44+
*
45+
* @param <T>
46+
* the type of the object being matched
47+
* @return a matcher that matches reflective elements with exactly the given level of visibility
48+
*/
49+
@SuppressWarnings("unchecked")
50+
public static <T> Matcher<T> isProtected()
51+
{
52+
// Each matcher is stateless and can match any type (the generic <T> is for type safety at the use site),
53+
// so it's fine to cast the non-reifiable generic type here at runtime and re-use the same instance.
54+
return (Matcher<T>) PROTECTED;
55+
}
56+
57+
/**
58+
* Matchers reflective elements that have package-protected visibility.
59+
* Specifically, this matcher only matches elements not marked with any of the visibility keywords {@code public}, {@code protected}, or {@code private}.
60+
* <br>
61+
* This method matches {@link Class} objects or other {@link java.lang.reflect.Member reflective objects}
62+
* like {@link java.lang.reflect.Field} or {@link java.lang.reflect.Method} used in reflection.
63+
* Any other kind of object, or {@code null} values, do not match (but will not cause an Exception).
64+
*
65+
* @param <T>
66+
* the type of the object being matched
67+
* @return a matcher that matches reflective elements with exactly the given level of visibility
68+
*/
69+
@SuppressWarnings("unchecked")
70+
public static <T> Matcher<T> isPackageProtected()
71+
{
72+
// Each matcher is stateless and can match any type (the generic <T> is for type safety at the use site),
73+
// so it's fine to cast the non-reifiable generic type here at runtime and re-use the same instance.
74+
return (Matcher<T>) PACKAGE_PROTECTED;
75+
}
76+
77+
/**
78+
* Matchers reflective elements that have private visibility.
79+
* Specifically, this matcher only matches elements marked with the keyword {@link private}.
80+
* <br>
81+
* This method matches {@link Class} objects or other {@link java.lang.reflect.Member reflective objects}
82+
* like {@link java.lang.reflect.Field} or {@link java.lang.reflect.Method} used in reflection.
83+
* Any other kind of object, or {@code null} values, do not match (but will not cause an Exception).
84+
*
85+
* @param <T>
86+
* the type of the object being matched
87+
* @return a matcher that matches reflective elements with exactly the given level of visibility
88+
*/
89+
@SuppressWarnings("unchecked")
90+
public static <T> Matcher<T> isPrivate()
91+
{
92+
// Each matcher is stateless and can match any type (the generic <T> is for type safety at the use site),
93+
// so it's fine to cast the non-reifiable generic type here at runtime and re-use the same instance.
94+
return (Matcher<T>) PRIVATE;
95+
}
96+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
</head>
6+
<body>
7+
<p>Matchers that perform checks on reflective elements, such as Class&lt;?&gt; objects</p>
8+
</body>
9+
</html>

hamcrest/src/main/java/org/hamcrest/visibility/Visibility.java

Lines changed: 0 additions & 20 deletions
This file was deleted.

hamcrest/src/main/java/org/hamcrest/visibility/VisibilityMatchers.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

hamcrest/src/main/java/org/hamcrest/visibility/VisibilityUtils.java

Lines changed: 0 additions & 58 deletions
This file was deleted.

hamcrest/src/main/java/org/hamcrest/visibility/package.html

Lines changed: 0 additions & 9 deletions
This file was deleted.

hamcrest/src/test/java/org/hamcrest/visibility/IsPackageProtectedTest.java renamed to hamcrest/src/test/java/org/hamcrest/reflection/IsPackageProtectedTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.hamcrest.visibility;
1+
package org.hamcrest.reflection;
22

33

44
import org.hamcrest.AbstractMatcherTest;
@@ -8,8 +8,8 @@
88
import java.lang.reflect.Field;
99
import java.lang.reflect.Method;
1010

11-
import static org.hamcrest.visibility.VisibilityMatchers.isPackageProtected;
12-
import static org.hamcrest.visibility.VisibilityMatchers.isPublic;
11+
import static org.hamcrest.reflection.VisibilityMatchers.isPackageProtected;
12+
import static org.hamcrest.reflection.VisibilityMatchers.isPublic;
1313

1414
@SuppressWarnings("unused")
1515
public class IsPackageProtectedTest extends AbstractMatcherTest

hamcrest/src/test/java/org/hamcrest/visibility/IsPrivateTest.java renamed to hamcrest/src/test/java/org/hamcrest/reflection/IsPrivateTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.hamcrest.visibility;
1+
package org.hamcrest.reflection;
22

33

44
import org.hamcrest.AbstractMatcherTest;
@@ -8,8 +8,8 @@
88
import java.lang.reflect.Field;
99
import java.lang.reflect.Method;
1010

11-
import static org.hamcrest.visibility.VisibilityMatchers.isPrivate;
12-
import static org.hamcrest.visibility.VisibilityMatchers.isPublic;
11+
import static org.hamcrest.reflection.VisibilityMatchers.isPrivate;
12+
import static org.hamcrest.reflection.VisibilityMatchers.isPublic;
1313

1414
@SuppressWarnings("unused")
1515
public class IsPrivateTest extends AbstractMatcherTest

0 commit comments

Comments
 (0)