ModelMapper is a library built specifically for mapping structurally similar heterogeneous objects onto each other. In other words, two different types of objects that have similarly named and typed fields. Thus, it naturally lends itself to your problem.
Unfortunately, it does not have support for Java 8's Optional wrappers built-in.
Thankfully, ModelMapper does allow you to specify custom converters.
Please read more about ModelMapper: https://modelmapper.org/
My code below is loosely based on: https://stackoverflow.com/a/29060055/2045291
Optional<T> --> T
Note: you may want to verify the type of the Optional's contents matches the destination type.
import org.modelmapper.spi.*;
import java.util.Optional;
public class OptionalExtractingConverter implements ConditionalConverter<Optional, Object> {
@Override
public MatchResult match(Class<?> aClass, Class<?> aClass1) {
if (Optional.class.isAssignableFrom(aClass) && !Optional.class.isAssignableFrom(aClass1)) {
return MatchResult.FULL;
}
return MatchResult.NONE;
}
@Override
public Object convert(MappingContext<Optional, Object> context) {
final Optional<?> source = context.getSource();
if (source != null && source.isPresent()) {
final MappingContext<?, ?> childContext = context.create(source.get(), context.getDestinationType());
return context.getMappingEngine().map(childContext);
}
return null;
}
}
import org.modelmapper.ModelMapper;
import java.util.Optional;
public class MappingService {
private static final ModelMapper modelMapper = new ModelMapper();
static {
modelMapper.typeMap(OptionalObject.class, NonOptionalObject.class)
.setPropertyConverter(new OptionalExtractingConverter());
}
public static void main(String[] args) {
OptionalObject optionalObject = new OptionalObject(Optional.of("test"));
NonOptionalObject nonOptionalObject = modelMapper.map(optionalObject, NonOptionalObject.class);
System.out.println("⭐️ RESULT: " + nonOptionalObject.getName());
}
}
Optional
field)import java.util.Optional;
public class OptionalObject {
private Optional<String> name;
public OptionalObject() {
}
public OptionalObject(final Optional<String> name) {
this.name = name;
}
public Optional<String> getName() {
return name;
}
public void setName(Optional<String> name) {
this.name = name;
}
}
Optional
field)public class NonOptionalObject {
private String name;
public NonOptionalObject() {
}
public NonOptionalObject(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}