Merge pull request #31323 from onobc

* gh-31323:
  Add PropertyMapper.to(...) API designed for immutable instances

Closes gh-31323
pull/31796/head
Phillip Webb 2 years ago
commit df381c51be

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.NoSuchElementException;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -52,6 +53,7 @@ import org.springframework.util.function.SingletonSupplier;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Chris Bono
* @since 2.0.0 * @since 2.0.0
*/ */
public final class PropertyMapper { public final class PropertyMapper {
@ -280,7 +282,7 @@ public final class PropertyMapper {
/** /**
* Complete the mapping by passing any non-filtered value to the specified * 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 * @param consumer the consumer that should accept the value if it's not been
* filtered * 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. * Complete the mapping by creating a new instance from the non-filtered value.
* @param <R> the resulting type * @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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 Phillip Webb
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Chris Bono
*/ */
class PropertyMapperTests { class PropertyMapperTests {
@ -207,6 +208,20 @@ class PropertyMapperTests {
assertThat(result).isEqualTo("123"); 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> { static class Count<T> implements Supplier<T> {
private final Supplier<T> source; 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