Skip to content

Commit

Permalink
Makes Objenesis dependency explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
jqno committed Sep 23, 2024
1 parent 60cb1e6 commit 000d5fb
Show file tree
Hide file tree
Showing 34 changed files with 296 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.objenesis.ObjenesisStd;

public class RecordInstantiatorTest {

@Test
public void instantiateRecord() {
Instantiator<?> instantiator = Instantiator.of(SimpleRecord.class);
Instantiator<?> instantiator = Instantiator.of(SimpleRecord.class, new ObjenesisStd());
Object simpleRecord = instantiator.instantiate();
assertEquals(SimpleRecord.class, simpleRecord.getClass());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import java.util.Map;
import nl.jqno.equalsverifier.internal.reflection.ClassProbe;
import org.junit.jupiter.api.Test;
import org.objenesis.ObjenesisStd;

public class RecordInstanceCreatorTest {

@Test
public void instanceCreator() throws NoSuchFieldException {
ClassProbe<SomeRecord> probe = new ClassProbe<>(SomeRecord.class);
InstanceCreator<SomeRecord> sut = new InstanceCreator<>(probe);
InstanceCreator<SomeRecord> sut = new InstanceCreator<>(probe, new ObjenesisStd());

Field x = SomeRecord.class.getDeclaredField("x");
Field z = SomeRecord.class.getDeclaredField("z");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
import nl.jqno.equalsverifier.internal.reflection.FieldIterable;
import nl.jqno.equalsverifier.internal.reflection.Instantiator;
import org.junit.jupiter.api.Test;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

public class RecordObjectAccessorCopyingTest {

private Objenesis objenesis = new ObjenesisStd();

@Test
public void copyHappyPath() {
Object original = instantiate(SimpleRecord.class);
Expand Down Expand Up @@ -41,11 +45,11 @@ private <T> RecordObjectAccessor<T> create(T object) {
}

private <T> T instantiate(Class<T> type) {
return Instantiator.of(type).instantiate();
return Instantiator.of(type, objenesis).instantiate();
}

private <T> T copyOf(T from) {
return create(from).copy();
return create(from).copy(objenesis);
}

record SimpleRecord(int i, String s) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.objenesis.ObjenesisStd;

public class RecordObjectAccessorScramblingTest {

Expand All @@ -22,7 +23,7 @@ public class RecordObjectAccessorScramblingTest {
@BeforeEach
public void setup() throws Exception {
factoryCache = JavaApiPrefabValues.build();
valueProvider = new VintageValueProvider(factoryCache);
valueProvider = new VintageValueProvider(factoryCache, new ObjenesisStd());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@
import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

public class RecordObjectAccessorTest {

private static final LinkedHashSet<TypeTag> EMPTY_TYPE_STACK = new LinkedHashSet<>();
private Objenesis objenesis;
private Object recordInstance;

@BeforeEach
public void setUp() throws Exception {
Constructor<?> constructor =
SimpleRecord.class.getDeclaredConstructor(int.class, String.class);
constructor.setAccessible(true);
objenesis = new ObjenesisStd();
recordInstance = constructor.newInstance(42, "hello");
}

Expand All @@ -42,29 +46,35 @@ public void get() {

@Test
public void fail_whenConstructorThrowsNpe() {
Object instance = Instantiator.of(NpeThrowingConstructorRecord.class).instantiate();
Object instance = Instantiator
.of(NpeThrowingConstructorRecord.class, objenesis)
.instantiate();

ExpectedException
.when(() -> accessorFor(instance).copy())
.when(() -> accessorFor(instance).copy(objenesis))
.assertThrows(ReflectionException.class)
.assertMessageContains("Record:", "failed to run constructor", "Warning.NULL_FIELDS");
}

@Test
public void fail_whenConstructorThrowsOnZero() {
Object instance = Instantiator.of(ZeroThrowingConstructorRecord.class).instantiate();
Object instance = Instantiator
.of(ZeroThrowingConstructorRecord.class, objenesis)
.instantiate();

ExpectedException
.when(() -> accessorFor(instance).copy())
.when(() -> accessorFor(instance).copy(objenesis))
.assertThrows(ReflectionException.class)
.assertMessageContains("Record:", "failed to run constructor", "Warning.ZERO_FIELDS");
}

@Test
public void fail_whenConstructorThrowsOnSomethingElse() {
Object instance = Instantiator.of(OtherThrowingConstructorRecord.class).instantiate();
Object instance = Instantiator
.of(OtherThrowingConstructorRecord.class, objenesis)
.instantiate();

VintageValueProvider vp = new VintageValueProvider(JavaApiPrefabValues.build());
VintageValueProvider vp = new VintageValueProvider(JavaApiPrefabValues.build(), objenesis);
ExpectedException
.when(() -> accessorFor(instance).scramble(vp, TypeTag.NULL, EMPTY_TYPE_STACK))
.assertThrows(ReflectionException.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
import nl.jqno.equalsverifier.internal.util.ListBuilders;
import nl.jqno.equalsverifier.internal.util.PrefabValuesApi;
import nl.jqno.equalsverifier.internal.util.Validations;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

public final class ConfiguredEqualsVerifier implements EqualsVerifierApi<Void> {

private final EnumSet<Warning> warningsToSuppress;
private final FactoryCache factoryCache;
private boolean usingGetClass;
private Function<String, String> fieldnameToGetter;
private final Objenesis objenesis = new ObjenesisStd();

/** Constructor. */
public ConfiguredEqualsVerifier() {
Expand Down Expand Up @@ -64,7 +67,7 @@ public ConfiguredEqualsVerifier suppress(Warning... warnings) {
/** {@inheritDoc} */
@Override
public <S> ConfiguredEqualsVerifier withPrefabValues(Class<S> otherType, S red, S blue) {
PrefabValuesApi.addPrefabValues(factoryCache, otherType, red, blue);
PrefabValuesApi.addPrefabValues(factoryCache, objenesis, otherType, red, blue);
return this;
}

Expand Down Expand Up @@ -125,6 +128,7 @@ public <T> SingleTypeEqualsVerifierApi<T> forClass(Class<T> type) {
type,
EnumSet.copyOf(warningsToSuppress),
factoryCache,
objenesis,
usingGetClass,
fieldnameToGetter
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import nl.jqno.equalsverifier.internal.reflection.FieldCache;
import nl.jqno.equalsverifier.internal.util.*;
import nl.jqno.equalsverifier.internal.util.Formatter;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

/**
* Helps to construct an {@link EqualsVerifier} test with a fluent API.
Expand All @@ -39,15 +41,27 @@ public class SingleTypeEqualsVerifierApi<T> implements EqualsVerifierApi<T> {
private Set<String> ignoredAnnotationClassNames = new HashSet<>();
private List<T> equalExamples = new ArrayList<>();
private List<T> unequalExamples = new ArrayList<>();
private final Objenesis objenesis;

/**
* Constructor.
*
* @param type The class for which the {@code equals} method should be tested.
*/
public SingleTypeEqualsVerifierApi(Class<T> type) {
this(type, new ObjenesisStd());
}

/**
* Constructor.
*
* @param type The class for which the {@code equals} method should be tested.
* @param objenesis To instantiate non-record classes.
*/
public SingleTypeEqualsVerifierApi(Class<T> type, Objenesis objenesis) {
this.type = type;
actualFields = FieldNameExtractor.extractFieldNames(type);
this.actualFields = FieldNameExtractor.extractFieldNames(type);
this.objenesis = objenesis;
}

/**
Expand All @@ -56,6 +70,7 @@ public SingleTypeEqualsVerifierApi(Class<T> type) {
* @param type The class for which the {@code equals} method should be tested.
* @param warningsToSuppress A list of warnings to suppress in {@code EqualsVerifier}.
* @param factoryCache Factories that can be used to create values.
* @param objenesis To instantiate non-record classes.
* @param usingGetClass Whether {@code getClass} is used in the implementation of the {@code
* equals} method, instead of an {@code instanceof} check.
* @param converter A function that converts from field name to getter name.
Expand All @@ -64,10 +79,11 @@ public SingleTypeEqualsVerifierApi(
Class<T> type,
EnumSet<Warning> warningsToSuppress,
FactoryCache factoryCache,
Objenesis objenesis,
boolean usingGetClass,
Function<String, String> converter
) {
this(type);
this(type, objenesis);
this.warningsToSuppress = EnumSet.copyOf(warningsToSuppress);
this.factoryCache = this.factoryCache.merge(factoryCache);
this.usingGetClass = usingGetClass;
Expand All @@ -83,7 +99,7 @@ public SingleTypeEqualsVerifierApi(
List<T> equalExamples,
List<T> unequalExamples
) {
this(type);
this(type, new ObjenesisStd());
this.equalExamples = equalExamples;
this.unequalExamples = unequalExamples;
}
Expand All @@ -105,7 +121,7 @@ public SingleTypeEqualsVerifierApi<T> suppress(Warning... warnings) {
/** {@inheritDoc} */
@Override
public <S> SingleTypeEqualsVerifierApi<T> withPrefabValues(Class<S> otherType, S red, S blue) {
PrefabValuesApi.addPrefabValues(factoryCache, otherType, red, blue);
PrefabValuesApi.addPrefabValues(factoryCache, objenesis, otherType, red, blue);
return this;
}

Expand All @@ -127,7 +143,7 @@ public <S> SingleTypeEqualsVerifierApi<T> withPrefabValuesForField(
S red,
S blue
) {
PrefabValuesApi.addPrefabValuesForField(fieldCache, type, fieldName, red, blue);
PrefabValuesApi.addPrefabValuesForField(fieldCache, objenesis, type, fieldName, red, blue);
withNonnullFields(fieldName);
return this;
}
Expand Down Expand Up @@ -409,14 +425,13 @@ private String buildErrorMessage(String description, boolean showUrl) {
}

private void performVerification() {
ObjenesisWrapper.reset();
if (type.isEnum() || type.isInterface()) {
return;
}
Validations.validateClassCanBeVerified(type);

Configuration<T> config = buildConfig();
Context<T> context = new Context<>(config, factoryCache, fieldCache);
Context<T> context = new Context<>(config, factoryCache, fieldCache, objenesis);
Validations.validateProcessedAnnotations(
type,
config.getAnnotationCache(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import nl.jqno.equalsverifier.internal.util.ObjenesisWrapper;
import org.objenesis.Objenesis;

/**
* Instantiates objects of a given class.
Expand All @@ -33,28 +33,31 @@ public final class Instantiator<T> {
private static final String FALLBACK_PACKAGE_NAME = getPackageName(Instantiator.class);

private final Class<T> type;
private final Objenesis objenesis;

/** Private constructor. Call {@link #of(Class)} to instantiate. */
private Instantiator(Class<T> type) {
private Instantiator(Class<T> type, Objenesis objenesis) {
this.type = type;
this.objenesis = objenesis;
}

/**
* Factory method.
*
* @param <T> The class on which {@link Instantiator} operates.
* @param type The class on which {@link Instantiator} operates. Should be the same as T.
* @param objenesis To instantiate non-record classes.
* @return An {@link Instantiator} for {@link #type}.
*/
public static <T> Instantiator<T> of(Class<T> type) {
public static <T> Instantiator<T> of(Class<T> type, Objenesis objenesis) {
if (SealedTypesHelper.isSealed(type)) {
Class<T> concrete = SealedTypesHelper.findInstantiableSubclass(type).get();
return Instantiator.of(concrete);
return Instantiator.of(concrete, objenesis);

Check warning on line 55 in equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/Instantiator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 55 without causing a test to fail

replaced return value with null for of (0 tests run NullReturnValsMutator)
}
if (Modifier.isAbstract(type.getModifiers())) {
return new Instantiator<>(giveDynamicSubclass(type, "", b -> b));
return new Instantiator<>(giveDynamicSubclass(type, "", b -> b), objenesis);

Check warning on line 58 in equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/Instantiator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to a lambda on line 58 without causing a test to fail

replaced return value with null for 1st lambda in of (34 tests run NullReturnValsMutator)
}
return new Instantiator<>(type);
return new Instantiator<>(type, objenesis);
}

/**
Expand All @@ -66,7 +69,7 @@ public static <T> Instantiator<T> of(Class<T> type) {
* @return An object of type T.
*/
public T instantiate() {
return ObjenesisWrapper.getObjenesis().newInstance(type);
return objenesis.newInstance(type);
}

/**
Expand All @@ -76,7 +79,7 @@ public T instantiate() {
*/
public T instantiateAnonymousSubclass() {
Class<T> proxyClass = giveDynamicSubclass(type);
return ObjenesisWrapper.getObjenesis().newInstance(proxyClass);
return objenesis.newInstance(proxyClass);
}

public static <S> Class<S> giveDynamicSubclass(Class<S> superclass) {
Expand Down
Loading

0 comments on commit 000d5fb

Please sign in to comment.