Add PropertyMapper.to(...) API designed for immutable instances

Add a new `to` method on `PropertyMapper` designed to work with
immutable instances. The new method takes an existing instance and
a mapping `BiFunction`.

See gh-31323

Co-authored-by: Phillip Webb <pwebb@vmware.com>
pull/31796/head
Chris Bono 2 years ago committed by Phillip Webb
parent e291b8fdcb
commit 8c70acc3c3

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.boot.context.properties;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@ -52,6 +53,7 @@ import org.springframework.util.function.SingletonSupplier;
*
* @author Phillip Webb
* @author Artsiom Yudovin
* @author Chris Bono
* @since 2.0.0
*/
public final class PropertyMapper {
@ -280,7 +282,7 @@ public final class PropertyMapper {
/**
* Complete the mapping by passing any non-filtered value to the specified
* consumer.
* consumer. The method is designed to be used with mutable objects.
* @param consumer the consumer that should accept the value if it's not been
* filtered
*/
@ -292,6 +294,24 @@ public final class PropertyMapper {
}
}
/**
* Complete the mapping for any non-filtered value by apply the given function to
* an existing instance and returning a new one. For filtered values, the
* {@code instance} parameter is returned unchanged. The method is designed to be
* used with immutable objects.
* @param <R> the result type
* @param instance the current instance
* @param mapper the mapping function
* @return a new mapped instance or the original instance
* @since 3.0.0
*/
public <R> R to(R instance, BiFunction<R, T, R> mapper) {
Assert.notNull(instance, "Instance must not be null");
Assert.notNull(mapper, "Mapper must not be null");
T value = this.supplier.get();
return (!this.predicate.test(value)) ? instance : mapper.apply(instance, value);
}
/**
* Complete the mapping by creating a new instance from the non-filtered value.
* @param <R> the resulting type

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
*
* @author Phillip Webb
* @author Artsiom Yudovin
* @author Chris Bono
*/
class PropertyMapperTests {
@ -207,6 +208,20 @@ class PropertyMapperTests {
assertThat(result).isEqualTo("123");
}
@Test
void toImmutableReturnsNewInstance() {
Immutable instance = this.map.from("Spring").toInstance(Immutable::of);
instance = this.map.from("123").as(Integer::valueOf).to(instance, Immutable::withAge);
assertThat(instance).hasToString("Spring 123");
}
@Test
void toImmutableWhenFilteredReturnsOriginalInstance() {
Immutable instance = this.map.from("Spring").toInstance(Immutable::of);
instance = this.map.from("123").when("345"::equals).as(Integer::valueOf).to(instance, Immutable::withAge);
assertThat(instance).hasToString("Spring null");
}
static class Count<T> implements Supplier<T> {
private final Supplier<T> source;
@ -257,4 +272,30 @@ class PropertyMapperTests {
}
static class Immutable {
private final String name;
private final Integer age;
Immutable(String name, Integer age) {
this.name = name;
this.age = age;
}
public Immutable withAge(Integer age) {
return new Immutable(this.name, age);
}
@Override
public String toString() {
return "%s %s".formatted(this.name, this.age);
}
static Immutable of(String name) {
return new Immutable(name, null);
}
}
}

Loading…
Cancel
Save