Better way for using builder pattern with optional values? - java

We are using the builder pattern to create some input for service, and it looks like something like this (simplified):
final SomeInput input = SomeInput.builder()
.withSomeId(....)
.withSomeState(....)
...
.build();
There's some attribute that we want to set in SomeInput, but only if it is present. So after creating the object, I do something like this:
Optional<String> secondaryId = infoProvider.getSecondaryId();
if (secondaryId.isPresent()) {
input.setSecondaryId(secondaryId.get());
}
I was wondering:
a) Is there a better/cleaner way to do this?
b) If I do need to do it this way, can I avoid the "if" statement and utilize some functionality with Optional?
(Note: I cannot change the builder itself, and I cannot that the secondaryId is a String, but that what we retrieve from infoProvider is an optional)

A little bit cleaner would be to use ifPresent
secondaryId.ifPresent(input::setSecondaryId);
but that's pretty much the best you can get with these requirements.

I was just facing the same problem as the OP and came up with this abstraction, which integrates directly with the builder instead of later modifying the object via setters. It would work the same with a model that instead of builders just offers "wither" methods.
(using lombok)
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Modifier<T> {
private final T value;
public static <T> Modifier<T> modify(T initialValue) {
return new Modifier<>(initialValue);
}
public <U> Modifier<T> ifPresent(Optional<U> optional, BiFunction<T, U, T> modifier) {
return modify(optional.map(input -> modifier.apply(value, input)).orElse(value));
}
public T get() {
return value;
}
}
Applied to the OP's example this would be used like this (again using lombok for generating the builder):
import static Modifier.modify;
import static org.junit.Assert.assertEquals;
class ModifierTest {
#Value
#Builder
static class SomeInput {
String id;
String secondaryId;
String state;
}
SomeInput constructSomeInput(Optional<String> maybeSecondaryId, Optional<String> maybeState) {
final SomeInput result = modify(SomeInput.builder().id("myId"))
.ifPresent(maybeSecondaryId, (builder, secondaryId) -> builder.secondaryId(secondaryId))
.ifPresent(maybeState, (builder, state) -> builder.state(state))
.get()
.build();
return result;
}
#Test
public void shouldBuildSomeInputWithSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.of("mySecondaryId");
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals("mySecondaryId", result.getSecondaryId());
assertEquals("myState", result.getState());
}
#Test
public void shouldBuildSomeInputWithoutSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.empty();
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals(null, result.getSecondaryId());
assertEquals("myState", result.getState());
}
}

Related

How to organize and test code in functional style in Java

I have an OOP approach to calculating a special code. There is a list of strategies that uses the chain of responsibility approach to calculate my value;
interface ChainStrategy {
Strategy getNext();
String getCode(SomeDto dto);
default String getDefaultVlue() {
return "";
};
}
class StrategyA implements ChainStrategy {
Strategy next;
StrategyA() {}
StrategyA(Strategy next) {
this.next = next;
}
Strategy getNext() {
return next;
}
public String getCode(SomeDto dto) {
if(dto.isA()) {
String result = dto.getA();
//this code could be placed in the abstract class to fulfill DRY
if(result == null) {
if(next!=null) {
result = next.getCode(dto);
}
else {
result = getDefaultVlue();
}
}
return result;
}
}
class StrategyB implements ChainStrategy {
// mostly the same code with different result calculation logic
}
class Client {
ChainStrategy strategy = new StrategyA(new StrategyB());
System.out.println(strategy.getCode())
}
}
This is "Java < 8" code that meets SOLID principles and can be easily tested. Usually, the real logic is more complicated than just dto.getA()
But it is just a chain of functions so I rewrite it:
interface ChainStrategy {
String getCode(SomeDto dto);
}
class CombineStrategy implements ChainStrategy {
private static final Function<SomeDto, Optional<String>> STRATEGY_A = dto -> Optional.of(dto).filter(SomeDto::isA).map(SomeDto::getA());
private static final Function<SomeDto, Optional<String>> STRATEGY_B = dto -> Optional.of(dto).filter(SomeDto::isB).map(SomeDto::getB());
private static final Function<SomeDto, String> STRATEGY_DEFAULT = dto -> "";
String getCode(SomeDto dto) {
Stream.of(STRATEGY_A, STRATEGY_B).map(st->st.apply(dto))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseGet(() -> STRATEGY_DEFAULT.apply(dto));
}
}
And my questions:
This code has problems with a single responsibility and "open-close" principles. And I can't test my functions individually. But creating separate classes for my functions looks like an overhead. Do we need these principles in functional programming?
I can rewrite "String getCode" to another static function. And store all these functions as a static Util class. But I don't want to lose ability to dynamically substitute my ChainFunction in the runtime. How do people combine static functions and dynamic binding in functional languages?

How to dynamic search with Criteria API in Java?

I want to dynamic search with Criteria API in Java.
In the code I wrote, we need to write each entity in the url bar in JSON. I don't want to write "plaka".
The URL : <localhost:8080/api/city/query?city=Ankara&plaka=> I want to only "city" or "plaka"
Here we need to write each entity, even if we are going to search with only 1 entity. Type Entity and it should be empty.
My code is as below. Suppose there is more than one entity, what I want to do is to search using a single entity it wants to search. As you can see in the photo, I don't want to write an entity that I don't need. can you help me what should I do?
My code in Repository
public interface CityRepository extends JpaRepository<City, Integer> , JpaSpecificationExecutor<City> {
}
My code in Service
#Service
public class CityServiceImp implements CityService{
private static final String CITY = "city";
private static final String PLAKA = "plaka";
#Override
public List<City> findCityByNameAndPlaka(String cityName, int plaka) {
GenericSpecification genericSpecification = new GenericSpecification<City>();
if (!cityName.equals("_"))
genericSpecification.add(new SearchCriteria(CITY,cityName, SearchOperation.EQUAL));
if (plaka != -1)
genericSpecification.add(new SearchCriteria(PLAKA,plaka, SearchOperation.EQUAL));
return cityDao.findAll(genericSpecification);
}
#Autowired
CityRepository cityDao;
My code in Controller
#RestController
#RequestMapping("api/city")
public class CityController {
#Autowired
private final CityService cityService;
public CityController(CityService cityService) {
this.cityService = cityService;
#GetMapping("/query")
public List<City> query(#RequestParam String city, #RequestParam String plaka){
String c = city;
int p;
if (city.length() == 0)
c = "_";
if (plaka.length() == 0) {
p = -1;
}
else
p = Integer.parseInt(plaka);
return cityService.findCityByNameAndPlaka(c,p);
}
My code in SearchCriteria
public class SearchCriteria {
private String key;
private Object value;
private SearchOperation operation;
public SearchCriteria(String key, Object value, SearchOperation operation) {
this.key = key;
this.value = value;
this.operation = operation;
}
public String getKey() {
return key;
}
public Object getValue() {
return value;
}
public SearchOperation getOperation() {
return operation;
}
My code in GenericSpecification
public class GenericSpecification<T> implements Specification<T> {
private List<SearchCriteria> list;
public GenericSpecification() {
this.list = new ArrayList<>();
}
public void add(SearchCriteria criteria){
list.add(criteria);
}
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
for (SearchCriteria criteria : list) {
if (criteria.getOperation().equals(SearchOperation.GREATER_THAN)) {
predicates.add(builder.greaterThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN)) {
predicates.add(builder.lessThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.GREATER_THAN_EQUAL)) {
predicates.add(builder.greaterThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN_EQUAL)) {
predicates.add(builder.lessThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.NOT_EQUAL)) {
predicates.add(builder.notEqual(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.EQUAL)) {
predicates.add(builder.equal(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.MATCH)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
"%" + criteria.getValue().toString().toLowerCase() + "%"));
} else if (criteria.getOperation().equals(SearchOperation.MATCH_END)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
criteria.getValue().toString().toLowerCase() + "%"));
}
}
return builder.and(predicates.toArray(new Predicate[0]));
}
My code in SearchOperation
public enum SearchOperation {
GREATER_THAN,
LESS_THAN,
GREATER_THAN_EQUAL,
LESS_THAN_EQUAL,
NOT_EQUAL,
EQUAL,
MATCH,
MATCH_END,
}
The good thing about the Criteria API is that you can use the CriteriaBuilder to build complex SQL statements based on the fields that you have. You can combine multiple criteria fields using and and or statements with ease.
How I approached something similar int he past is using a GenericDao class that takes a Filter that has builders for the most common operations (equals, qualsIgnoreCase, lessThan, greaterThan and so on). I actually have something similar in an open-source project I started: https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/dao/GenericDao.java
https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/filter/JPAFilter.java
Next, the implicit DAO class extends this GenericDao and when I want to do an operation (ex: find a user with the provided username) and there I create a Filter.
Now, the magic is in the filter. This is the one that creates the Predicate.
In your request, you will receive something like this: field1=something&field2=somethingElse and so on. The value can be preceded by the '<' or '>' if you want smaller or greater and you initialize your filter with the values. If you can retrieve the parameters as a Map<String, String>, even better.
Now, for each field in the request, you create a predicate using the helper methods from the JPAFilter class and return he resulted Predicate. In the example below I assume that you don't have it as a Map, but as individual fields (it is easy to adapt the code for a Map):
public class SearchFilter extends JPAFilter {
private Optional<String> field1 = Optional.empty();
private Optional<String> field2 = Optional.empty();
#Override
public Predicate getPredicate(CriteriaBuilder criteriaBuilder, Root root) {
Predicate predicateField1 = field1.map(f -> equals(criteriaBuilder, root, "field1", f)).orElse(null);
Predicate predicateField2 = field2.map(f -> equals(criteriaBuilder, root, "field2", f)).orElse(null);
return andPredicateBuilder(criteriaBuilder, predicateField1, predicateField2);
}
}
Now, I have the fields as Optional since in this case I assumed that you have them as Optional in your request mapping (Spring has this) and I know it is a bit controversial to have Optional as input params, but in this case I think it is acceptable (more on this here: https://petrepopescu.tech/2021/10/an-argument-for-using-optional-as-input-parameters/)
The way the andPredicateBuilder() is made is that it works properly even if one of the supplied predicates is null. Also, I made s simple mapping function, adjust to include for < and >.
Now, in your DAO class, just supply the appropriate filter:
public class SearchDao extends GenericDAO {
public List<MyEntity> search(Filter filter) {
return get(filter);
}
}
Some adjustments need to be made (this is just starter code), like an easier way to initialize the filter (and doing this inside the DAO) and making sure that that the filter can only by applied for the specified entity (probably using generics, JPAFIlter<T> and having SearchFilter extends JPAFilter<MyEntity>). Also, some error handling can be added.
One disadvantage is that the fields have to match the variable names in your entity class.

How do I test Function's code when it's passed as method parameter?

Is it possible to test code that is written in lambda function that is passed inside the method process?
#AllArgsConstructor
public class JsonController {
private final JsonElementProcessingService jsonElementProcessingService;
private final JsonObjectProcessingService jsonObjectProcessingService;
private final JsonArrayProcessingService jsonArrayProcessingService;
public void process(String rawJson) {
jsonElementProcessingService.process(json -> {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}, rawJson);
}
}
Since the lambda is lazy the function is not invoked (Function::apply) when I call JsonController::process so is there any way to check that jsonArrayProcessingService::process is called?
#RunWith(JMockit.class)
public class JsonControllerTest {
#Injectable
private JsonElementProcessingService jsonElementProcessingService;
#Injectable
private JsonObjectProcessingService jsonObjectProcessingService;
#Injectable
private JsonArrayProcessingService jsonArrayProcessingService;
#Tested
private JsonController jsonController;
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
// how check here that jsonArrayProcessingService was invoked?
}
}
Just make it testable (and readable) by converting it to a method:
public void process(String rawJson) {
jsonElementProcessingService.process(this::parse, rawJson);
}
Object parse(String json) {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}
The relevant guiding principles I personally follow are:
anytime my lambdas require curly brackets, convert them to a method
organise code so that it can be unit tested
You may need to change the return type of the parse method to match whatever your processing services (which you didn’t show) return.
Given its relatively-basic redirection logic, don't you just want to confirm which of the #Injectables got called:
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
new Verifications() {{
jsonArrayProcessingService.process(withInstanceOf(JsonArray.class));
}};
}

Graceful alternative to nested Optional.map?

I have multiple Optionals that must be mapped to a POJO. Is there a better alternative than the following?
class SimplePojo {
private String stringField;
private Integer integerField;
// All args. constructor, getter, setter
}
Optional<String> stringOptional = ...
Optional<Integer> integerOptional = ...
Optional<SimplePojo> simplePojoOptional = stringOptional.flatMap(
string -> integerOptional.map(integer -> new SimplePojo(string, integer)))
I have reduced the problem to 2 Optionals in the above example to keep it short. But I actually have 3 Optionals with more on the way. I am afraid the last line can easily become unwieldy soon.
Please note: Use of functional frameworks like Vavr or Functional Java is not an option for me.
How about using a Builder ?
class SimplePojo {
public static class Builder {
private String stringField;
public Builder withStringField(String str) {
this.stringField = str;
return this;
}
// and other "with" methods...
public Optional<SimplePojo> build() {
if (stringField == null || anotherField == null /* and so forth */) {
return Optional.empty();
} else {
return Optional.of(new SimplePojo(this));
}
}
}
private final String stringField;
/* private constructor, so client code has to go through the Builder */
private SimplePojo(Builder builder) {
this.stringField = builder.stringField;
// etc.
}
}
Then you could use it as follows:
SimplePojo.Builder builder = new SimplePojo.builder();
optionalStringField.ifPresent(builder::withStringField);
// etc.
return builder.build();
I do not see any advantage from pursuing the functional style this way here. see three options:
ONE: If you can alter the SimplePojo class and if this scenario is a common one, you might consider to add a factory method to the SimplePojo:
class SimplePojo {
public static Optional<SimplePojo> of(final Optional<String> stringField, final Optional<Integer> integerField) {
if (stringField.isPresent() && integerField.isPresent()) {
return new SimplePojo(stringField.get(), integerField.get());
else
return Optional.empty();
}
}
TWO: If you cannot alter the SimplePojo, you might want to create this as a utility method somewhere else. If you need this pattern only in one class, make the method private in this class!
THREE: If you need to do this only once or twice, I would prefer the if...then construction from the first option over the functional notation you used for the sake of readability:
final Optional<SimplePojo> simplePojoOptional;
if (stringField.isPresent() && integerField.isPresent()) {
simplePojoOptional = new SimplePojo(stringField.get(), integerField.get());
else
simplePojoOptional = Optional.empty();

Annotation processor: get all enum values from a TypeMirror or TypeElement

I don't understand how I can retrieve the Enum values in an annotation processor.
My annotation is a custom Java Bean Validation annotation:
#StringEnumeration(enumClass = UserCivility.class)
private String civility;
On my annotation processor, I can access to instances of these:
javax.lang.model.element.AnnotationValue
javax.lang.model.type.TypeMirror
javax.lang.model.element.TypeElement
I know it contains the data about my enum since I can see that in debug mode. I also see ElementKind == Enum
But I want to get all the names for that Enum, can someone help me please.
Edit: I don't have access to the Class object of this Enum, because we are in an annotation processor, and not in standart Java reflection code. So I can't call Class#getEnumConstants() or EnumSet.allOf(MyEnum.class) unless you tell me how I can get the Class object from the types mentioned above.
I found a solution (this uses Guava):
class ElementKindPredicate<T extends Element> implements Predicate<T> {
private final ElementKind kind;
public ElementKindPredicate(ElementKind kind) {
Preconditions.checkArgument(kind != null);
this.kind = kind;
}
#Override
public boolean apply(T input) {
return input.getKind().equals(kind);
}
}
private static final ElementKindPredicate ENUM_VALUE_PREDICATE = new ElementKindPredicate(ElementKind.ENUM_CONSTANT);
public static List<String> getEnumValues(TypeElement enumTypeElement) {
Preconditions.checkArgument(enumTypeElement.getKind() == ElementKind.ENUM);
return FluentIterable.from(enumTypeElement.getEnclosedElements())
.filter(ENUM_VALUE_PREDICATE)
.transform(Functions.toStringFunction())
.toList();
}
The answer given by Sebastian is correct, but if you're using Java 8 or above, you can use the following (cleaner) approach than using Google Guava.
List<String> getEnumValues(TypeElement enumTypeElement) {
return enumTypeElement.getEnclosedElements().stream()
.filter(element -> element.getKind().equals(ElementKind.ENUM_CONSTANT))
.map(Object::toString)
.collect(Collectors.toList());
}
Here's a complete example. Note the use of getEnumConstants on the enum values.
public class Annotate {
public enum MyValues {
One, Two, Three
};
#Retention(RetentionPolicy.RUNTIME)
public #interface StringEnumeration {
MyValues enumClass();
}
#StringEnumeration(enumClass = MyValues.Three)
public static String testString = "foo";
public static void main(String[] args) throws Exception {
Class<Annotate> a = Annotate.class;
Field f = a.getField("testString");
StringEnumeration se = f.getAnnotation(StringEnumeration.class);
if (se != null) {
System.out.println(se.enumClass());
for( Object o : se.enumClass().getClass().getEnumConstants() ) {
System.out.println(o);
}
}
}
}
This will print out:
Three
One
Two
Three

Categories

Resources