lundi 26 août 2019

Implementation for object converter design pattern using generics

I'm trying to create a generic object converter, for my dto <-> entity classes. I have created an abstract class with two functions representing both conversions and then extended it in my concrete converter class.

But I would like to have a generic conversion service, where I could register all of my converters during bootup and then conveniently call a single method to handle the conversions between each other.

This is what I have come up so far:

Converter abstract class

public abstract class Converter<D, E> {

  private final Function<D, E> fromFirstToSecond;
  private final Function<E, D> fromSecondToFirst;

  public Converter(final Function<D, E> fromFirstToSecond, final Function<E, D> fromSecondToFirst) {
    this.fromFirstToSecond = fromFirstToSecond;
    this.fromSecondToFirst = fromSecondToFirst;
  }

  public final E convertFromFirstToSecond(final D first) {
    return fromFirstToSecond.apply(first);
  }

  public final D convertFromSecondToFirst(final E second) {
    return fromSecondToFirst.apply(second);
  }

}

Converter concrete class

public class MyConverter extends Converter<MyDTO, MyEntity> {

    public OrderConverter() {
        super(
            MyConverter::fromDTOToEntity,
            MyConverter::fromEntityToDTO
        );
    }

    private static MyEntity fromDTOToEntity(MyDTO dto) {
        return MyEntity.builder()
            .field1(dto.getField1())
            .field2(dto.getField2())
            .build();
    }

    private static MyDTO fromEntityToDTO(MyEntity entity) {
        return MyDTO.builder()
            .field1(entity.getField1())
            .field2(entity.getField2())
            .build();
    }

}

And I would like to achieve something like this (this is where I need HELP):

@Configuration
public class ConverterConfiguration {

  @Bean
  public ConverterService converterService() {
    ConverterService converterService = new ConverterService();
    converterService.registerConverter(new MyConverter());
    // Register any other converter...
    return converterService;
  }

}

The service would look something like this:

public class ConverterService {

  private Map<Key, Converter<?, ?>> converters = new ConcurrentReferenceHashMap<>();

  public void registerConverter(Converter<?, ?> converter) {
    this.converterCache.put(key, converter);
  }

  protected <I, O> I mapBetweenTypes(final O from, final Class<I> clazz) {
    // Based on the parameters I should be able to figure out which function to get from the map and then call (convertFromFirstToSecond or convertFromSecondToFirst)
    // return this.converters.get(key).convertFromFirstToSecond(from);
    return this.converters.get(key).convertFromSecondToFirst(from);
  }

}

Aucun commentaire:

Enregistrer un commentaire