Skip to content

Commit f5cc1bf

Browse files
authored
Create GenericMappingDemo.java
1 parent 55e768c commit f5cc1bf

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

GenericMappingDemo.java

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
public class GenericMappingDemo {
2+
3+
static class A {
4+
private Integer integerA;
5+
private String stringA;
6+
private Float floatA;
7+
8+
public A(final Integer integerA, final String stringA, final Float floatA) {
9+
this.integerA = integerA;
10+
this.stringA = stringA;
11+
this.floatA = floatA;
12+
}
13+
14+
public Integer getIntegerA() {
15+
return integerA;
16+
}
17+
18+
public void setIntegerA(final Integer integerA) {
19+
this.integerA = integerA;
20+
}
21+
22+
public String getStringA() {
23+
return stringA;
24+
}
25+
26+
public void setStringA(final String stringA) {
27+
this.stringA = stringA;
28+
}
29+
30+
public Float getFloatA() {
31+
return floatA;
32+
}
33+
34+
public void setFloatA(final Float floatA) {
35+
this.floatA = floatA;
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return "A{integerA=" + integerA + ", stringA='" + stringA + "', floatA=" + floatA + '}';
41+
}
42+
}
43+
44+
static class B {
45+
private Integer integerB;
46+
private String stringB;
47+
48+
public Integer getIntegerB() {
49+
return integerB;
50+
}
51+
52+
public void setIntegerB(final Integer integerB) {
53+
this.integerB = integerB;
54+
}
55+
56+
public String getStringB() {
57+
return stringB;
58+
}
59+
60+
public void setStringB(final String stringB) {
61+
this.stringB = stringB;
62+
}
63+
64+
@Override
65+
public String toString() {
66+
return "B{integerB=" + integerB + ", stringB='" + stringB + '\'' + '}';
67+
}
68+
}
69+
70+
static class C {
71+
private Float floatC;
72+
private String stringC;
73+
74+
public Float getFloatC() {
75+
return floatC;
76+
}
77+
78+
public void setFloatC(final Float floatC) {
79+
this.floatC = floatC;
80+
}
81+
82+
public String getStringC() {
83+
return stringC;
84+
}
85+
86+
public void setStringC(final String stringC) {
87+
this.stringC = stringC;
88+
}
89+
90+
@Override
91+
public String toString() {
92+
return "C{floatC=" + floatC + ", stringC='" + stringC + "'}";
93+
}
94+
}
95+
96+
static class GenericMapping<C, T> {
97+
final int id;
98+
final Class<C> type;
99+
final Function<C, T> getter;
100+
final BiConsumer<C, T> setter;
101+
102+
public GenericMapping(final int id,
103+
final Class<C> type,
104+
final Function<C, T> getter,
105+
final BiConsumer<C, T> setter) {
106+
this.id = id;
107+
this.type = type;
108+
this.getter = getter;
109+
this.setter = setter;
110+
}
111+
}
112+
113+
static class Mapper {
114+
// All mappings by class and id
115+
private final Map<Class<?>, Map<Integer, GenericMapping<?, ?>>> mappings
116+
= new HashMap<>();
117+
118+
public void addMapping(GenericMapping<?, ?> mapping) {
119+
mappings.computeIfAbsent(mapping.type,
120+
c -> new TreeMap<>()).put(mapping.id, mapping);
121+
}
122+
123+
/**
124+
* Map values from one object to another,
125+
* using any mapping ids that apply to both classes
126+
* @param from The object to transfer values from
127+
* @param to The object to transfer values to
128+
*/
129+
public <From, To> void map(From from, To to) {
130+
Map<Integer, GenericMapping<?, ?>> getters
131+
= mappings.get(from.getClass());
132+
Map<Integer, GenericMapping<?, ?>> setters
133+
= mappings.get(to.getClass());
134+
if (getters == null || setters == null) {
135+
// Nothing to do
136+
return;
137+
}
138+
139+
// Create a set with the ids in both getters and
140+
// setters, i.e. the mappings that apply
141+
Set<Integer> ids = new HashSet<>(getters.keySet());
142+
ids.retainAll(setters.keySet());
143+
144+
// Transfer all mappings
145+
for (Integer id : ids) {
146+
GenericMapping<From, ?> getter
147+
= (GenericMapping<From, ?>) getters.get(id);
148+
GenericMapping<To, ?> setter
149+
= (GenericMapping<To, ?>) setters.get(id);
150+
transfer(from, to, getter, setter);
151+
}
152+
}
153+
154+
private <From, To, V> void transfer(final From from,
155+
final To to, final GenericMapping<From, ?> getter,
156+
final GenericMapping<To, V> setter) {
157+
// This will throw an exception if the mappings are invalid
158+
final V value = (V) getter.getter.apply(from);
159+
setter.setter.accept(to, value);
160+
}
161+
}
162+
163+
public static void main(String[] args) {
164+
final Mapper mapper = new Mapper();
165+
166+
// Mapping definition for class A
167+
mapper.addMapping(new GenericMapping<>(1, A.class,
168+
A::getIntegerA, A::setIntegerA));
169+
mapper.addMapping(new GenericMapping<>(2, A.class,
170+
A::getStringA, A::setStringA));
171+
mapper.addMapping(new GenericMapping<>(3, A.class,
172+
A::getFloatA, A::setFloatA));
173+
174+
// Mapping definition for class B
175+
mapper.addMapping(new GenericMapping<>(1, B.class,
176+
B::getIntegerB, B::setIntegerB));
177+
mapper.addMapping(new GenericMapping<>(2, B.class,
178+
B::getStringB, B::setStringB));
179+
180+
// Mapping definition for class C
181+
mapper.addMapping(new GenericMapping<>(2, C.class,
182+
C::getStringC, C::setStringC));
183+
mapper.addMapping(new GenericMapping<>(3, C.class,
184+
C::getFloatC, C::setFloatC));
185+
186+
// Use the mappings
187+
A a = new A(7, "foo", 3.7f);
188+
B b = new B();
189+
C c = new C();
190+
191+
System.out.printf("A before map: %s%n", a);
192+
System.out.printf("B before map: %s%n", b);
193+
System.out.printf("C before map: %s%n", c);
194+
195+
// This will transfer a.integerA to b.integerB and a.stringA to b.stringB
196+
mapper.map(a, b);
197+
// This will transfer a.stringA to c.stringC and a.floatA to c.floatC
198+
mapper.map(a, c);
199+
200+
System.out.println();
201+
System.out.printf("A after map: %s%n", a);
202+
System.out.printf("B after map: %s%n", b);
203+
System.out.printf("C after map: %s%n", c);
204+
}
205+
}

0 commit comments

Comments
 (0)