Created
January 27, 2021 17:37
-
-
Save PiotrJander/0bbeb53aa445effc2ec2b2483a9f4921 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import lombok.Data; | |
import lombok.Value; | |
import org.springframework.lang.Nullable; | |
import java.lang.reflect.Method; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** @noinspection unchecked, rawtypes */ | |
class Scratch { | |
interface Converter<From, To> { | |
To convert(From from); | |
ConverterSignature getSignature(); | |
} | |
// TODO support subtyping | |
// TODO special handling of newtypes | |
// TODO skip generic types and higher order converters for now | |
// class IdentityConverter<A> implements Converter<A, A> { | |
// | |
// @Override | |
// public A convert(A a) { | |
// return a; | |
// } | |
// } | |
@Data | |
static class FooId { | |
private String id; | |
} | |
@Data | |
static class Foo { | |
private FooId id; | |
private String name; | |
} | |
@Data | |
static class FooDto { | |
private String id; | |
private String name; | |
} | |
static class FooIdToStringConverter implements Converter<FooId, String> { | |
@Override | |
public String convert(FooId fooId) { | |
return fooId.getId(); | |
} | |
@Override | |
public ConverterSignature getSignature() { | |
return new ConverterSignature(FooId.class, String.class); | |
} | |
} | |
@Value | |
static class ConverterSignature { | |
private Class<?> from; | |
private Class<?> to; | |
} | |
private Map<ConverterSignature, Converter<?, ?>> converterRegistry = new HashMap<>(); | |
@Nullable <From, To> Converter<From, To> getConverter(Class<From> from, Class<To> to) { | |
//noinspection unchecked | |
return (Converter<From, To>) converterRegistry.get(new ConverterSignature(from, to)); | |
} | |
void registerConverter(Converter<?, ?> converter) { | |
converterRegistry.put(converter.getSignature(), converter); | |
} | |
<From, To> Converter<From, To> createConverter(Class<From> fromClass, Class<To> toClass) { | |
return new Converter<>() { | |
@SuppressWarnings("checkstyle:MagicNumber") | |
@Override | |
public To convert(From from) { | |
try { | |
To result = toClass.getDeclaredConstructor().newInstance(); | |
for (Method method : toClass.getMethods()) { | |
if (method.getName().startsWith("set")) { | |
Method setter = method; | |
Class toFieldType = setter.getParameterTypes()[0]; | |
String fieldName = setter.getName().substring(3); | |
String getterName = "get" + fieldName; | |
Method getter = fromClass.getMethod(getterName); | |
Class fromFieldType = getter.getReturnType(); | |
Object fromValue = getter.invoke(from); | |
if (fromFieldType.equals(toFieldType)) { | |
setter.invoke(result, fromValue); | |
} else { | |
Converter converter = getConverter(fromFieldType, toFieldType); | |
Object toValue = converter.convert(fromValue); | |
setter.invoke(result, toValue); | |
} | |
} | |
} | |
return result; | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
@Override | |
public ConverterSignature getSignature() { | |
return new ConverterSignature(fromClass, toClass); | |
} | |
}; | |
} | |
public static void main(String[] args) { | |
Scratch scratch = new Scratch(); | |
scratch.registerConverter(new FooIdToStringConverter()); | |
Converter<Foo, FooDto> converter = scratch.createConverter(Foo.class, FooDto.class); | |
Foo foo = new Foo(); | |
FooId id = new FooId(); | |
id.setId("foo"); | |
foo.setId(id); | |
foo.setName("bar"); | |
FooDto from = converter.convert(foo); | |
System.out.println(from.toString()); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment