79296072

Date: 2024-12-20 03:06:36
Score: 0.5
Natty:
Report link

Background

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.

Credit

Please read more about ModelMapper: https://modelmapper.org/

My code below is loosely based on: https://stackoverflow.com/a/29060055/2045291

Code

Custom Converter for 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;
    }
}

Test

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());
    }

}

Source Object (w/ 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;
    }

}

Destination Object (w/ non-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;
    }

}
Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: cbush06