Skip to content

Commit

Permalink
Merge pull request #58 from datalorax/bug/Pop-53-dont-throw-from-getG…
Browse files Browse the repository at this point in the history
…enericType-if-inaccessible-v1.,1

Merge #53 and #55 across to release/1.1
big-andy-coates committed May 11, 2015

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 6171f66 + 8bf54a4 commit 547cc03
Showing 9 changed files with 284 additions and 74 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -157,7 +157,7 @@ If you're using [Maven](http://maven.apache.org/), then add the following to you
<dependency>
<groupId>com.github.datalorax.populace</groupId>
<artifactId>populace-core</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</dependency>
</dependencies>
```
@@ -167,15 +167,15 @@ If you're using [Gradle](http://www.gradle.org/), then add the following to your

```
dependencies {
compile 'com.github.datalorax.populace:populace-core:1.1.0'
compile 'com.github.datalorax.populace:populace-core:1.1.1'
}
```

# SBT
If you're using [SBT](http://code.google.com/p/simple-build-tool/), then add the following to your project:

```
libraryDependencies += "com.github.datalorax.populace" % "populace-core" % "1.1.0"
libraryDependencies += "com.github.datalorax.populace" % "populace-core" % "1.1.1"
```

## Javadocs
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -16,6 +16,8 @@





apply plugin: 'com.github.kt3k.coveralls'
apply plugin: 'jacoco'

@@ -54,7 +56,7 @@ subprojects {
apply plugin: 'maven'

group = "com.github.datalorax.populace"
version = "1.1.0"
version = "1.1.1"

sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
109 changes: 63 additions & 46 deletions populace-core/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# Populace-core

This page provides information on how to use and customise the core graph walking and populating features of Populace
This page provides information on how to use and customise the core graph [walking](#graph-walking) and
[populating](#graph-populating) features of Populace

## Graph Walking

Put simply, you can use `GraphWalker` to walk the fields and (container) elements of an object graph.
Put simply, you can use `GraphWalker` to walk the fields and elements of an object graph.

You provide [`Visitors`](#visitors) that will be called back as each field/element that is encountered. You can
* **Fields** An instance of a class exposes the *fields* declared by the class definition.
* **Elements** Where a field is a container type e.g. `List`, `Map`, etc, then the field can have child *elements*.

You provide [`Visitors`](#visitors) that will be called for each field/element that is encountered. You can
optionally control what fields and elements are included / excluded from the walk by installing [`Filters`](#filters),
and you can control what fields and elements are exposed from custom types by installing [`Inspectors`](#inspectors).
and you can control what fields and elements are exposed from a specific type by installing [`Inspectors`](#inspectors).

### Filters

Filters can be installed to stop specific fields or elements from being walked, (or visiting). Field and Element filters
Filters can be installed to stop specific fields or elements from being walked, (or visited). Field and Element filters
are installed when building a walker instance, as shown below:

```java
@@ -35,9 +39,10 @@ being visited more than once.

The `InstanceTracker` is not installed by default, but can be installed as shown below.

**Note**: The instance tracker is stateful and mutable. Therefore, multiple calls to `walk` that re-use the same
`InstanceTracker` will carry over the list of visited instances from one walk to the next. This is generally not
desired. If not desired, ensure you call `clear` on the instance tracker between each walk.
**Note**: The instance tracker is stateful and mutable. It is therefore one of the few parts of Populace that is not
thread-safe. Also, multiple calls to `walk` on the same walker will carry over the list of visited instances from one
walk to the next. This is generally not desired. If not desired, ensure you call `clear` on the instance tracker
between each walk.

```java
InstanceTracker tracker = new InstanceTracker();
@@ -50,16 +55,17 @@ GraphWalker walker = builder

### Inspectors

`Inspectors` are similar to [`Filters`](#filters) in some ways. Where as [`Filters`](#filters) control which of the
types / instances fields and elements are walked, `Inspectors` actual define the set of exposed fields/elements.
`Inspectors` are similar to [`Filters`](#filters) in some ways. Where as [`Filters`](#filters) , given the list of fields
and elements a type exposed, controls which fields and elements should be walked, `Inspectors` actual define the set of
exposed fields/elements.

`Inspectors` should be generic, in that they should expose the fields and elements in a generic, none use-case specific,
manner, so that they can be reused across many use-cases and applications. On the other hand, Filters can to be specific
to the use-case.
`Inspectors` should exposed the fields and elements of a type and should be re-usable by others who use the same type.
Avoid implementing inspectors to expose only a subset. On the other hand, filters, or combinations of filters, can be
used to customise a walker to a specific use-case.

Populace defines a whole set of inspectors to cover most common types. (If you feel there is a inspector missing for
some common type then please raise a ticket, or even better a PR). You may need to write your own inspectors, especially
if you have custom container types that are not derived from the standard `List`, `Set` or `Map` interfaces.
Populace defines inspector to cover most common types. (If you feel there is a inspector missing for some common type
then please raise a ticket, or even better a PR). You may need to write your own inspectors, especially if you have
custom container types that are not derived from the standard `List`, `Set` or `Map` interfaces.

Inspectors are installed when building a walker. Inspectors can be installed to handle specific types, any subtype of
some type or any type within a package. See [Registering Customisations](#registering-customisations) for an
@@ -75,10 +81,11 @@ final GraphWalker walker = builder.withInspectors(builder.inspectors()

### Visitors

The visitors you install will be called back as each non-filtered field and element visited. The visitor can mutate the
value of the field/mutator if required, using the `setValue` methods on the supplied `FieldInfo`/`ElementInfo` instance.
The visitors you pass to the `walk` function will be called back as each non-filtered field and element is visited. The
visitor can mutate the value of the field/mutator if required, using the `setValue` methods on the supplied
`FieldInfo`/`ElementInfo` instance.

Visitors are passed to the `walk` method itself, like so:
Visitors are are passed to the `walk` method:

```java
walker.walk(typeToWalk, fieldVisitor, elementVisitor);
@@ -94,19 +101,18 @@ You can control this process by installing [`Mutators`](#mutators), which are re

### Mutators

Mutators allow you to install custom code to control how certain types are mutated, giving you complete control over how
Mutators allow you to install custom code to control how a type is mutated, giving you complete control over how
your object graphs are populated.

Populace comes complete with a lot of standard Mutators that can be composed to achieve most tasks, and you are free to
implement your own as needed. By default, a new populator comes pre-configured with a sensible set of mutators, that
Populace comes complete with standard Mutators that can be composed to achieve most tasks, and you are free to
implement your own as needed. By default, a new populator comes pre-configured with a sensible set of mutators that
will handle most common types, though these can be overridden if needed.

Mutators can be installed to mutate specific types, subtypes of some type, any type belonging to a package, and
default mutators for array and non-array types can also be configured. See
Mutators can be installed to mutate specific types, subtypes of some known super-type, and any type belonging to a package,
plus default mutators for array and non-array types can also be configured. See
[Registering Customisations](#registering-customisations) for an explanation of the different levels. See below for an
example:


```java
GraphPopulator.Builder builder = GraphPopulator.newBuilder();
GraphPopulator populator = builder
@@ -118,20 +124,20 @@ GraphPopulator populator = builder

### Instance Factories

Instance Factories allow you to install custom code to control how certain types are created. Populace needs this to
allow fields that are currently null, or container types that are currently empty, to be populated.
Instance Factories allow you to install custom code to control how a type is created. Populace needs this to allow
fields that are currently null, or container types that are currently empty, to be populated.

Populace comes complete with a lot of factories for standard types and any type that can be constructed using its
default constructor. For other types you will need to implement custom instance factories.
Populace comes complete with factories for standard types and any type that can be constructed using its default
constructor, for any other type you will need to implement and register an instance factory.

Instance factories can be installed for specific types, subtypes of some type, any type belonging to a package, and
Instance factories can be installed for specific types, subtypes of some super-type, any type belonging to a package, and
default factories for array and non-array types can also be configured. See
[Registering Customisations](#registering-customisations) for an explanation of the different levels.

In addition, a special type of instance factory, called a `NullObjectStrategy`, can be installed to handle any null
`Object` s i.e. fields or elements where no type information is available, i.e. they are either of type `Object` or their
type information can't be resolved, and the current value is null. In such situations Populace does not have enough
information to populate the element, but you may chose to do handle this however you like by installing a custom
type information can't be resolved, and the current value is `null`. In such situations Populace does not have enough
information to populate the element, but you may chose to handle this however you like by installing a custom
`NullObjectStrategy`.
Instance factories can be installed as shown below:
@@ -154,32 +160,38 @@ Many of the customisations available in Populace, such as `Mutators`, `Inspector
e.g. `MyType<Integer>`, or a specific array type e.g. `long[]`. Such handlers will be used in preference to any other handler.
* **super types** i.e. you can register a handler for a super type such as `List` and it will be used to handle any
derived types that do not have a more specific handler installed.
* **packages** i.e. you can register a handler to handle any types that belong to specific package e.g. `java.lang.util`.
The handler will be used for any type that belongs to the package that do not have a more specific handler installed.
* **default** this is the default handler to use if the type is not an array type and no other, more specific, handler is
installed.
* **packages** i.e. you can register a handler to handle any types that belong to a specific package e.g.
`java.lang.util`. The handler will be used for any type that belongs to the package, including child packages, that do
not have a more specific handler installed.
* **default** this is the default handler to be use if the type is not an array type and no other, more specific,
handler is installed.
* **array default** arrays are treated slightly differently. The default array handler will be used where no specific
handler is registered for an array type.
To understand what type will be used at runtime to look up suitable handlers you will first need to understand how Populace
[determines runtime type information](#runtime-type-resolution).
To understand what type informamtion will be used at runtime to look up suitable handlers you will first need to
understand how Populace [determines runtime type information](#runtime-type-resolution).
# Runtime-type resolution
Populace determines the runtime type of a field or element by making use of all compile-time and runtime type information
available. Fields and elements with a null value are treated differently to non-null values, as non-null values have
Populace determines the runtime type of a field or element by making at both the compile-time and runtime type information
available. Fields and elements with a null value are treated differently to non-null values, as non-null values have
additional runtime type information.
**Note** to make use of runtime time information the fields Populace is walking need to be accessible. It is strongly
advised that you install the `SetAccessibleFieldVisitor` to ensure fields are accessible. However, this is optional as
Populace does support running with a security manager that would not allow the field to be made accessible. In such a
situation Populace will only use compile-time type information.
## Null fields
When the value of the field is null the only information available is the compile type type of the field.
If the compile time type of the field is a normal class, e.g. `long` or `List`, then Populace will use this type
information when looking up configured customisations.
If the compile time type of the field is a parameterised type, e.g. `Map<String,Integer>`, then Populace will use the
full parameterised type when looking up customisations. In addition, if any of the type arguments are type variables,
or have bounds, e.g. consider the field 'example' in the following code snippet below, Populace will use all
available type information in parent/containing classes to resolve the type variables or bounds to concrete types.
full parameterised type when looking up customisations. In addition, if any of the type arguments are type variables or
wildcards, e.g. consider the field 'example' in the following code snippet below, Populace will use all available type
information in parent/containing classes to resolve the type variables and any bounds to concrete types.
```java
class SomeClass<T> {
@@ -197,15 +209,20 @@ class SomeClass<T> {
```
## Non-null fields
When the value of the field is not null, then Populace has additional type information available to it, and it will use
this information to resolve the type of the field to a more specific type, if possible.
When the value of the field is not null, and the field is accessible, then Populace has additional type information
available to it, and it will use this information to resolve the type of the field to a more specific type, if possible.
Because Populace can only make use of the fields runtime type information if the field is accessible it is strongly
advised that you install the `SetAccessibleFieldVisitor`, to ensure all fields are accessible, unless there is a good
reason not to. Without `SetAccessibleFieldVisitor` installed, Populace will not be able to use runtime type
information. In which case, the logic for determining type information is the [same as if the field was null](#null-fields).
If the runtime type of the field is a normal class, then the more specific runtime type will be used.
If the runtime type of the field is a type that has type arguments, then Populace will parameterise the runtime type
using all available type information in the field's compile-time type and parent/container type information, e.g. if a
field type is `List<String>` and the field value is an instance of `ArrayList`, then Populace will resolve the type to
`ArrayList<String>`. Populace will also attempt to resolve any type variables and bounds, as needed.
`ArrayList<String>`. Populace will also attempt to resolve all type variables and bounds.

## Null elements

Original file line number Diff line number Diff line change
@@ -87,9 +87,8 @@ public int hashCode() {
@Override
public String toString() {
return "ElementInfo{" +
"element=" + element +
", typeResolver=" + typeResolver +
", path=" + path +
"path=" + path.getPath() +
", type=" + getGenericType() +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -31,25 +31,26 @@ public class FieldInfo {
private final RawField field;
private final Object owningInstance;
private final TypeResolver typeResolver;
private final PathProvider pathProvider;
private final PathProvider path;

/**
* Construct a new FieldInfo object
*
* @param field the raw field this instance should augment
* @param owningInstance the instance from which to get / set the current value of this field
* @param typeResolver the resolver to use to resolve generic types
* @param pathProvider the provider of the path to this instance.
* @param path the provider of the path to this instance.
*/
public FieldInfo(final RawField field, final Object owningInstance, final TypeResolver typeResolver, final PathProvider pathProvider) {
public FieldInfo(final RawField field, final Object owningInstance,
final TypeResolver typeResolver, final PathProvider path) {
Validate.notNull(field, "field null");
Validate.notNull(owningInstance, "owningInstance null");
Validate.notNull(typeResolver, "typeResolver null");
Validate.notNull(pathProvider, "pathProvider null");
Validate.notNull(path, "path null");
this.field = field;
this.owningInstance = owningInstance;
this.typeResolver = typeResolver;
this.pathProvider = pathProvider;
this.path = path;
}

/**
@@ -85,6 +86,12 @@ public Class<?> getType() {
* <li>For <b>non-primitive types with a null value</b> this method returns the resolved generic type of the field</li>
* <li>For <b>non-primitive types with a non-null value</b> this method returns the resolved generic type of the value</li>
* </ul>
*
* <b>Note: This method will make use of the runtime type information available within the fields value if the field
* is accessible. It is strongly recommended that you install the
* {@link org.datalorax.populace.core.walk.visitor.SetAccessibleFieldVisitor} so that Populace can make use of this
* additional type information</b>
*
* @return the generic type of the field
* @see RawField#getGenericType()
*/
@@ -93,9 +100,11 @@ public Type getGenericType() {
return field.getType();
}

final Object value = getValue();
if (value != null) {
return typeResolver.resolve(value.getClass());
if (isAccessible()) {
final Object value = getValue();
if (value != null) {
return typeResolver.resolve(value.getClass());
}
}

return typeResolver.resolve(field.getGenericType());
@@ -112,6 +121,14 @@ public Object getOwningInstance() {
return owningInstance;
}

/**
* @return true if field is accessible, false otherwise.
* @see RawField#isAccessible()
*/
public boolean isAccessible() {
return field.isAccessible();
}

/**
* @see RawField#ensureAccessible()
*/
@@ -128,7 +145,7 @@ public Object getValue() {
try {
return field.getValue(getOwningInstance());
} catch (ReflectiveOperationException e) {
throw new FieldAccessException(field, pathProvider, e);
throw new FieldAccessException(field, path, e);
}
}

@@ -143,7 +160,7 @@ public void setValue(Object value) {
try {
field.setValue(getOwningInstance(), value);
} catch (ReflectiveOperationException e) {
throw new FieldAccessException(field, pathProvider, e);
throw new FieldAccessException(field, path, e);
}
}

@@ -187,21 +204,20 @@ public boolean equals(final Object o) {
if (o == null || getClass() != o.getClass()) return false;

final FieldInfo that = (FieldInfo) o;
return pathProvider.getPath().equals(that.pathProvider.getPath());
return path.getPath().equals(that.path.getPath());
}

@Override
public int hashCode() {
return pathProvider.getPath().hashCode();
return path.getPath().hashCode();
}

@Override
public String toString() {

return "FieldInfo{" +
"field=" + field +
", owningInstance=" + owningInstance +
", typeResolver=" + typeResolver +
", path=" + pathProvider.getPath() +
"path=" + path.getPath() +
", type=" + getGenericType() +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -129,6 +129,15 @@ public <T extends Annotation> T getAnnotation(final Class<T> type) {
return annotationInspector.getAnnotation(field, type);
}

/**
* Determine if this field is accessible i.e. that its value can be retrieved and/or set.
*
* @return true if this field is accessible, false otherwise.
*/
public boolean isAccessible() {
return field.isAccessible();
}

/**
* Ensure the field represented by this {@code RawField} is accessible i.e that calls to {@link #getValue(Object)}
* and {@link #setValue(Object, Object)} won't through {@link java.lang.IllegalAccessException}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2015 Andrew Coates
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.datalorax.populace.core.walk;

import org.datalorax.populace.core.walk.field.RawField;
import org.testng.annotations.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class WalkerStackTest {
@Test
public void shouldStartPathWithRootObjectType() throws Exception {
// Given:
final WalkerStack root = WalkerStack.newStack("rootObject");

// Then:
assertThat(root.getPath(), is("String"));
}

@Test
public void shouldAppendFieldsToPath() throws Exception {
// Given:
final WalkerStack root = WalkerStack.newStack(new Object());
final RawField field = mock(RawField.class);
when(field.getGenericType()).thenReturn(Number.class);
when(field.getName()).thenReturn("fred");

// When:
final WalkerStack stack = root.push(field);

// Then:
assertThat(stack.getPath(), endsWith(".fred"));
}
}
Original file line number Diff line number Diff line change
@@ -26,6 +26,8 @@
import org.testng.annotations.Test;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
@@ -227,6 +229,7 @@ public void shouldReturnGenericTypeFromResolver() throws Exception {
@Test
public void shouldGetGenericTypeFromFieldIfValueNull() throws Exception {
// Given:
givenFieldIsAccessible();
givenFieldHasValue(null, Map.class);
when(field.getGenericType()).thenReturn(genericType);

@@ -237,10 +240,24 @@ public void shouldGetGenericTypeFromFieldIfValueNull() throws Exception {
verify(typeResolver).resolve(genericType);
}

@SuppressWarnings("unchecked")
@Test
public void shouldGetGenericTypeFromValueIfNotNull() throws Exception {
public void shouldGetGenericTypeFromFieldIfFieldInaccessible() throws Exception {
// Given:
givenFieldIsNotAccessible();
givenFieldHasValue("some-value");
when(field.getGenericType()).thenReturn(genericType);

// When:
fieldInfo.getGenericType();

// Then:
verify(typeResolver).resolve(genericType);
}

@Test
public void shouldGetGenericTypeFromValueIfNotNullAndAccessible() throws Exception {
// Given:
givenFieldIsAccessible();
givenFieldHasValue("some-value");

// When:
@@ -332,6 +349,7 @@ public void shouldOnlyUsePathInHashCode() throws Exception {
public void shouldIncludePathInToString() throws Exception {
// Given:
when(pathProvider.getPath()).thenReturn("some/path");
givenFieldHasValue("value");

// When:
final String string = fieldInfo.toString();
@@ -340,6 +358,65 @@ public void shouldIncludePathInToString() throws Exception {
assertThat(string, containsString("some/path"));
}

@Test
public void shouldIncludePrimitiveTypeInPath() throws Exception {
// Given:
givenFieldIsAccessible();
givenFieldHasType(long.class);

// When:
final String string = fieldInfo.toString();

// Then:
assertThat(string, containsString("long"));
}

@Test
public void shouldIncludeGenericTypeInPathIfAccessible() throws Exception {
// Given:
givenFieldIsAccessible();
givenFieldHasValue(new ArrayList(), List.class);
when(typeResolver.resolve(any(Type.class))).thenReturn(genericType);

// When:
final String string = fieldInfo.toString();

// Then:
assertThat(string, containsString("type=java.util.Map<K, V>"));
}

@Test
public void shouldIncludeNonGenericTypeOInPathIfInaccessible() throws Exception {
// Given:
givenFieldIsNotAccessible();
givenFieldHasType(Map.class);
when(typeResolver.resolve(any(Type.class))).thenReturn(genericType);

// When:
final String string = fieldInfo.toString();

// Then:
assertThat(string, containsString("type=java.util.Map<K, V>"));
}

@Test
public void shouldReturnInaccessible() throws Exception {
// Given:
givenFieldIsNotAccessible();

// Then:
assertThat("should be inaccessible if field is inaccessible", fieldInfo.isAccessible(), is(false));
}

@Test
public void shouldReturnAccessible() throws Exception {
// Given:
givenFieldIsAccessible();

// Then:
assertThat("should be accessible if field is accessible", fieldInfo.isAccessible(), is(true));
}

@Test
public void shouldEnsureFieldAccessible() throws Exception {
// When:
@@ -349,17 +426,25 @@ public void shouldEnsureFieldAccessible() throws Exception {
verify(field).ensureAccessible();
}

@SuppressWarnings("unchecked")
@Test
public void shouldTestEqualsAndHashCode() throws Exception {
// Given:
givenFieldHasValue("value");

final PathProvider otherPathProvider = mock(PathProvider.class, "other");
when(pathProvider.getPath()).thenReturn("somePath");
when(otherPathProvider.getPath()).thenReturn("differentPath");

final RawField otherField = mock(RawField.class, "other");
when(otherField.getType()).thenReturn((Class) long.class);

// Then:
new EqualsTester()
.addEqualityGroup(
new FieldInfo(field, owningInstance, typeResolver, pathProvider),
new FieldInfo(field, owningInstance, typeResolver, pathProvider),
new FieldInfo(mock(RawField.class, "other"), owningInstance, typeResolver, pathProvider),
new FieldInfo(otherField, owningInstance, typeResolver, pathProvider),
new FieldInfo(field, new Object(), typeResolver, pathProvider),
new FieldInfo(field, owningInstance, mock(TypeResolver.class, "other"), pathProvider))
.addEqualityGroup(
@@ -380,9 +465,21 @@ private void givenFieldHasValue(final Object value) throws IllegalAccessExceptio
givenFieldHasValue(value, value.getClass());
}

@SuppressWarnings("unchecked")
private void givenFieldHasValue(final Object value, Class type) throws IllegalAccessException {
private void givenFieldHasValue(final Object value, final Class type) throws IllegalAccessException {
when(field.getValue(anyObject())).thenReturn(value);
givenFieldHasType(type);
}

@SuppressWarnings("unchecked")
private void givenFieldHasType(final Class type) {
when(field.getType()).thenReturn(type);
}

private void givenFieldIsAccessible() {
when(field.isAccessible()).thenReturn(true);
}

private void givenFieldIsNotAccessible() {
when(field.isAccessible()).thenReturn(false);
}
}
Original file line number Diff line number Diff line change
@@ -114,6 +114,24 @@ public void shouldReturnValueFromAnnotationInspector() throws Exception {
assertThat(actual, is(expected));
}

@Test
public void shouldReturnInaccessible() throws Exception {
// Given:
field.setAccessible(false);

// Then:
assertThat("should be inaccessible if field is inaccessible", rawField.isAccessible(), is(false));
}

@Test
public void shouldReturnAccessible() throws Exception {
// Given:
field.setAccessible(true);

// Then:
assertThat("should be accessible if field is accessible", rawField.isAccessible(), is(true));
}

@Test
public void shouldEnsureAccessible() throws Exception {
// Given:

0 comments on commit 547cc03

Please sign in to comment.