spring-projects / spring-projects/spring-boot
Add simple API to JacksonTester for direct instantiation
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 81.5k
- Forks
- 42.7k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 65
Description
@JsonTest and json testers are hidden gems for tests with json.
Background
I have seen many test classes that create their own JsonUtils to load json files.
The JSON testers in org.springframework.boot.test.json could do it and they are more powerful.
However, the creation of the json testers, for example, JacksonTester is somewhat geared toward the usage with @JsonTest.
When I want to use it outside of @JsonTest, instantiation requires reflection based instance injection or a bit verbose constructor APIs.
JacksonTester<Foo> tester;
@BeforeEach
void beforeEach(){
// reflection based injection
JacksonTester.initFields(this, objectMapper);
}
@Test
void myTest() {
// it is not intuitive constructor to use
JacksonTester<Foo> tester = new JacksonTester<>(getClass(), ResolvableType.forClass(MySample.class), objectMappeer);
}
Proposal
To make direct instantiation simpler, it would be nice to add simple constructors or a builder.
For example, JacksonTester could have constructors that doesn't require resourceLoadClass argument:
// simple usage
JacksonTester(Class<T> type, ObjectMapper objectMapper)
// for fine tuning
JacksonTester(ResolvableType type, ObjectMapper objectMapper)
// for generics (above ResolvableType kind of covers it though)
JacksonTester(ParameterizedTypeReference<?> typeReference, ObjectMapper objectMapper)
Or with a builder:
// for simple class
JsonTester<MySample> tester = builder.type(MySamle.class).build();
// for collection
JsonTester<List<MySample>> tester = builder.forList(MySamle.class).build();
// for class with generics
JsonTester<Foo<Bar>> tester = builder.type(Foo.class, Bar.class).build();
This way, I can simply create an instance in a test method like:
@Test
void myTest() {
JacksonTester<Foo> tester = new JacksonTester<>(Foo.class, objectMapper);
}
Implementation Details
The current public constructor takes:
Class<?> resourceLoadClassResolvableType typeObjectMapper objectMapper
Within AbstractJsonMarshalTester, resourceLoadClass is enforced to be a non-null. However, it is essentially passed down to the ClassPathResource to get a classloader from the resourceLoadClass. In ClassPathResource, it is actually a nullable parameter. When the parameter is null, it falls back to the system class loader. I think in many cases it is fine, especially in test. Or, it could use the target type class to retrieve a classloader.
Passing ResolvableType as a constructor parameter is a bit unintuitive for direct instantiation. It could just take the target type class and internally convert it to a ResolvableType instance.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with JacksonTester and AbstractJsonMarshalTester, then inspect how the current resourceLoadClass and ResolvableType constructor are used; ClassPathResource provides the class-loader behavior described in the issue. Define and verify a direct-instantiation API that works outside @JsonTest, covering the selected simple and generic type cases without requiring a resource-load class.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100