Skip to content

Commit

Permalink
Fix ConstructorProperty not validated with annotations (#1119)
Browse files Browse the repository at this point in the history
  • Loading branch information
seongahjo authored Dec 11, 2024
1 parent 7c6b910 commit e77f8d2
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 25 deletions.
2 changes: 2 additions & 0 deletions docs/content/v1.1.x-kor/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ sectionStart
## v.1.1.6
Deprecate `Randoms.create(String)`, use `Randoms.setSeed(long)` instead.

Fix an instance generated by `ConstructorPropertiesArbitraryIntrospector` that was not validated by validation annotations.

sectionEnd

sectionStart
Expand Down
4 changes: 3 additions & 1 deletion docs/content/v1.1.x/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ weight: 100
---
sectionStart
## v.1.1.6
Deprecate `Randoms.create(String)`, use `Randoms.setSeed(long)` instead.
Deprecate `Randoms.create(String)`, use `Randoms.setSeed(long)` instead.

Fix an instance generated by `ConstructorPropertiesArbitraryIntrospector` that was not validated by validation annotations.

sectionEnd

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
import com.navercorp.fixturemonkey.api.property.ConstructorPropertyGeneratorContext;
import com.navercorp.fixturemonkey.api.property.FieldPropertyGenerator;
import com.navercorp.fixturemonkey.api.property.JavaBeansPropertyGenerator;
import com.navercorp.fixturemonkey.api.property.MethodParameterProperty;
import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.api.property.PropertyUtils;
import com.navercorp.fixturemonkey.api.property.TypeNameProperty;
import com.navercorp.fixturemonkey.api.type.TypeCache;
import com.navercorp.fixturemonkey.api.type.TypeReference;
import com.navercorp.fixturemonkey.api.type.Types;
Expand Down Expand Up @@ -239,7 +239,7 @@ private static List<Property> getMethodParameterProperties(
String resolvedParameterName = resolvedParameterNames.get(i);
TypeReference<?> resolvedTypeReference = resolvedParameterTypes.get(i);
properties.add(
new MethodParameterProperty(
new TypeNameProperty(
resolvedTypeReference.getAnnotatedType(),
resolvedParameterName,
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,8 @@ public List<Property> generateParameterProperties(ConstructorPropertyGeneratorCo
constructorPropertiesByName.put(
receiverParameter.getName(),
new ConstructorProperty(
receiverParameter.getAnnotatedType(),
new TypeNameProperty(receiverParameter.getAnnotatedType(), receiverParameter.getName(), null),
constructor,
receiverParameter.getName(),
null,
null
)
Expand All @@ -158,9 +157,8 @@ public List<Property> generateParameterProperties(ConstructorPropertyGeneratorCo
constructorPropertiesByName.put(
parameterName,
new ConstructorProperty(
fieldProperty.getAnnotatedType(),
fieldProperty,
constructor,
parameterName,
fieldProperty,
null
)
Expand All @@ -169,9 +167,8 @@ public List<Property> generateParameterProperties(ConstructorPropertyGeneratorCo
constructorPropertiesByName.put(
parameterName,
new ConstructorProperty(
parameterAnnotatedType,
new TypeNameProperty(parameterAnnotatedType, parameterName, null),
constructor,
parameterName,
fieldProperty,
null
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -37,28 +37,43 @@

@API(since = "0.4.2", status = Status.MAINTAINED)
public final class ConstructorProperty implements Property {
private final AnnotatedType annotatedType;
private final Property parameterProperty;
private final Constructor<?> constructor;
private final String parameterName;
@Nullable
private final Property fieldProperty;
private final List<Annotation> annotations;
private final Map<Class<? extends Annotation>, Annotation> annotationsMap;
@Nullable
private final Boolean nullable;

/**
* It is deprecated.
* Use {@link #ConstructorProperty(Property, Constructor, Property, Boolean)} instead.
*/
@Deprecated
public ConstructorProperty(
AnnotatedType annotatedType,
Constructor<?> constructor,
String parameterName,
@Nullable Property fieldProperty,
@Nullable Boolean nullable
) {
this.annotatedType = annotatedType;
this(new TypeNameProperty(annotatedType, parameterName, nullable), constructor, fieldProperty, nullable);
}

public ConstructorProperty(
Property parameterProperty,
Constructor<?> constructor,
@Nullable Property fieldProperty,
@Nullable Boolean nullable
) {
this.parameterProperty = parameterProperty;
this.constructor = constructor;
this.parameterName = parameterName;
this.fieldProperty = fieldProperty;
this.annotations = Arrays.asList(annotatedType.getAnnotations());
this.annotations = new ArrayList<>(parameterProperty.getAnnotations());
if (fieldProperty != null) {
this.annotations.addAll(fieldProperty.getAnnotations());
}
this.annotationsMap = this.annotations.stream()
.collect(Collectors.toMap(Annotation::annotationType, Function.identity(), (a1, a2) -> a1));
this.nullable = nullable;
Expand All @@ -71,7 +86,7 @@ public Type getType() {

@Override
public AnnotatedType getAnnotatedType() {
return this.annotatedType;
return this.parameterProperty.getAnnotatedType();
}

public Constructor<?> getConstructor() {
Expand All @@ -85,7 +100,7 @@ public Property getFieldProperty() {

@Override
public String getName() {
return this.parameterName;
return this.parameterProperty.getName();
}

@Override
Expand All @@ -102,7 +117,11 @@ public <T extends Annotation> Optional<T> getAnnotation(Class<T> annotationClass
@Nullable
@Override
public Boolean isNullable() {
return nullable;
if (nullable != null) {
return nullable;
}

return parameterProperty.isNullable();
}

@Override
Expand All @@ -114,16 +133,15 @@ public boolean equals(Object obj) {
return false;
}
ConstructorProperty that = (ConstructorProperty)obj;
return annotatedType.getType().equals(that.annotatedType.getType())
return parameterProperty.equals(that.parameterProperty.getType())
&& constructor.equals(that.constructor)
&& parameterName.equals(that.parameterName)
&& Objects.equals(fieldProperty, that.fieldProperty)
&& annotations.equals(that.annotations);
}

@Override
public int hashCode() {
return Objects.hash(annotatedType.getType(), constructor, parameterName, fieldProperty, annotations);
return Objects.hash(parameterProperty, constructor, fieldProperty, annotations);
}

@Nullable
Expand All @@ -139,10 +157,12 @@ public Object getValue(Object instance) {
@Override
public String toString() {
return "ConstructorProperty{"
+ "annotatedType=" + annotatedType
+ "parameterProperty=" + parameterProperty
+ ", constructor=" + constructor
+ ", parameterName='" + parameterName + '\''
+ ", fieldProperty=" + fieldProperty
+ ", annotations=" + annotations
+ ", annotationsMap=" + annotationsMap
+ ", nullable=" + nullable
+ '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

import javax.annotation.Nullable;

/**
* It is deprecated.
* Use {@link TypeNameProperty} instead.
*/
@Deprecated
public final class MethodParameterProperty implements Property {
private final AnnotatedType annotatedType;
@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Fixture Monkey
*
* Copyright (c) 2021-present NAVER Corp.
*
* 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 com.navercorp.fixturemonkey.api.property;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import javax.annotation.Nullable;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

/**
* It is a property has a type name.
* For example, It can be used to represent a type name of a class or method.
*/
@API(since = "1.1.6", status = Status.EXPERIMENTAL)
public final class TypeNameProperty implements Property {
private final AnnotatedType annotatedType;
private final String typeName;
@Nullable
private final Boolean nullable;

public TypeNameProperty(
AnnotatedType annotatedType,
String typeName,
@Nullable Boolean nullable
) {
this.annotatedType = annotatedType;
this.typeName = typeName;
this.nullable = nullable;
}

@Override
public Type getType() {
return annotatedType.getType();
}

@Override
public AnnotatedType getAnnotatedType() {
return annotatedType;
}

@Nullable
@Override
public String getName() {
return typeName;
}

@Override
public List<Annotation> getAnnotations() {
return Arrays.asList(annotatedType.getAnnotations());
}

@Nullable
@Override
public Object getValue(Object instance) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public Boolean isNullable() {
return nullable;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TypeNameProperty that = (TypeNameProperty)obj;
return Objects.equals(annotatedType, that.annotatedType)
&& Objects.equals(typeName, that.typeName)
&& Objects.equals(nullable, that.nullable);
}

@Override
public int hashCode() {
return Objects.hash(annotatedType, typeName, nullable);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ import com.navercorp.fixturemonkey.api.introspector.CompositeArbitraryIntrospect
import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector
import com.navercorp.fixturemonkey.api.property.FieldPropertyGenerator
import com.navercorp.fixturemonkey.api.property.JavaBeansPropertyGenerator
import com.navercorp.fixturemonkey.api.property.MethodParameterProperty
import com.navercorp.fixturemonkey.api.property.Property
import com.navercorp.fixturemonkey.api.property.PropertyUtils
import com.navercorp.fixturemonkey.api.property.TypeNameProperty
import com.navercorp.fixturemonkey.api.type.TypeReference
import com.navercorp.fixturemonkey.api.type.Types
import com.navercorp.fixturemonkey.kotlin.introspector.CompanionObjectFactoryMethodIntrospector
Expand Down Expand Up @@ -217,7 +217,7 @@ class KotlinInstantiatorProcessor :
): List<Property> = this.parameters
.filter { parameter -> parameter.kind != KParameter.Kind.INSTANCE }
.mapIndexed { index, kParameter ->
MethodParameterProperty(
TypeNameProperty(
resolvedParameterTypes[index].annotatedType,
resolvedParameterNames[index],
kParameter.type.isMarkedNullable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
import java.util.OptionalLong;
import java.util.Set;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Value;

import com.navercorp.fixturemonkey.tests.java.ImmutableJavaTestSpecs.Enum;
Expand Down Expand Up @@ -239,4 +244,12 @@ public String getValue() {
return value;
}
}

@Getter
@AllArgsConstructor
public class JavaxValidationObject {
@Max(100)
@Min(100)
private int value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@
import com.navercorp.fixturemonkey.api.type.TypeReference;
import com.navercorp.fixturemonkey.customizer.InnerSpec;
import com.navercorp.fixturemonkey.customizer.Values;
import com.navercorp.fixturemonkey.javax.validation.plugin.JavaxValidationPlugin;
import com.navercorp.fixturemonkey.resolver.ArbitraryBuilderCandidateFactory;
import com.navercorp.fixturemonkey.resolver.ArbitraryBuilderCandidateList;
import com.navercorp.fixturemonkey.tests.java.ConstructorAndPropertyTestSpecs.ConsturctorAndProperty;
import com.navercorp.fixturemonkey.tests.java.ConstructorTestSpecs.FieldAndConstructorParameterMismatchObject;
import com.navercorp.fixturemonkey.tests.java.ConstructorTestSpecs.JavaxValidationObject;
import com.navercorp.fixturemonkey.tests.java.ConstructorTestSpecs.SimpleContainerObject;
import com.navercorp.fixturemonkey.tests.java.ImmutableDepthTestSpecs.DepthStringValueList;
import com.navercorp.fixturemonkey.tests.java.ImmutableDepthTestSpecs.OneDepthStringValue;
Expand Down Expand Up @@ -1395,4 +1397,17 @@ void registerJavaTypebuilder() {

then(actual).isEqualTo(expected);
}

@RepeatedTest(TEST_COUNT)
void constructorValidator() {
FixtureMonkey sut = FixtureMonkey.builder()
.plugin(new JavaxValidationPlugin())
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.defaultNotNull(true)
.build();

JavaxValidationObject actual = sut.giveMeOne(JavaxValidationObject.class);

then(actual.getValue()).isEqualTo(100);
}
}

0 comments on commit e77f8d2

Please sign in to comment.