Skip to content

Commit c91fb19

Browse files
committed
Complete functionality
1 parent 37eede2 commit c91fb19

24 files changed

Lines changed: 681 additions & 18 deletions

pom.xml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@
8080
</properties>
8181

8282
<dependencies>
83+
<!-- provided -->
8384
<dependency>
84-
<groupId>pl.wavesoftware</groupId>
85-
<artifactId>eid-exceptions</artifactId>
86-
<version>1.2.0</version>
85+
<groupId>javax.persistence</groupId>
86+
<artifactId>javax.persistence-api</artifactId>
87+
<version>2.2</version>
88+
<scope>provided</scope>
8789
</dependency>
8890
<dependency>
8991
<groupId>org.projectlombok</groupId>
@@ -95,10 +97,18 @@
9597
<dependency>
9698
<groupId>org.mapstruct</groupId>
9799
<artifactId>mapstruct-jdk8</artifactId>
98-
<version>1.2.0.Final</version>
100+
<version>[1.2.0.Final,2.0.0)</version>
99101
<scope>provided</scope>
100102
</dependency>
101103

104+
<!-- runtime -->
105+
<dependency>
106+
<groupId>pl.wavesoftware</groupId>
107+
<artifactId>eid-exceptions</artifactId>
108+
<version>1.2.0</version>
109+
</dependency>
110+
111+
<!-- test -->
102112
<dependency>
103113
<groupId>junit</groupId>
104114
<artifactId>junit</artifactId>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import pl.wavesoftware.utils.mapstruct.CompositeContext.CompositeContextBuilder;
5+
import pl.wavesoftware.utils.mapstruct.cycles.CyclicGraphContext;
6+
import pl.wavesoftware.utils.mapstruct.jpa.JpaMappingContext;
7+
import pl.wavesoftware.utils.mapstruct.jpa.JpaMappingContextFactory;
8+
9+
import javax.annotation.Nullable;
10+
import java.util.function.Supplier;
11+
12+
/**
13+
* @author <a href="krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszyński</a>
14+
* @since 2018-05-03
15+
*/
16+
public abstract class AbstractCompositeContextProvider
17+
implements MapStructContextProvider<CompositeContext> {
18+
19+
@Override
20+
public CompositeContext createNewContext() {
21+
StoringMappingContext cyclicGraphCtx = new CyclicGraphContext();
22+
CompositeContextBuilder contextBuilder = CompositeContext.builder();
23+
Supplier<CompositeContext> contextSupplier = new StoringMappingContextSupplier(contextBuilder);
24+
Mappings.MappingsBuilder mappingsBuilder = Mappings.builder();
25+
for (MappingProvider<?, ?, ?> mappingProvider : getMappingProviders()) {
26+
mappingsBuilder.addMapping(mappingProvider.provide());
27+
}
28+
JpaMappingContext jpaContext = getJpaMappingContextFactory()
29+
.produce(
30+
contextSupplier,
31+
mappingsBuilder.build(),
32+
getIdentifierCollector()
33+
);
34+
35+
contextBuilder.addContext(cyclicGraphCtx);
36+
contextBuilder.addContext(jpaContext);
37+
38+
return contextSupplier.get();
39+
}
40+
41+
protected abstract JpaMappingContextFactory getJpaMappingContextFactory();
42+
protected abstract Iterable<MappingProvider<?, ?, ?>> getMappingProviders();
43+
protected abstract IdentifierCollector getIdentifierCollector();
44+
45+
@RequiredArgsConstructor
46+
private static final class StoringMappingContextSupplier implements Supplier<CompositeContext> {
47+
private final CompositeContextBuilder contextBuilder;
48+
@Nullable
49+
private CompositeContext context;
50+
51+
@Override
52+
public CompositeContext get() {
53+
if (context == null) {
54+
context = contextBuilder.build();
55+
}
56+
return context;
57+
}
58+
}
59+
}

src/main/java/pl/wavesoftware/utils/mapstruct/CompositeMappingContext.java renamed to src/main/java/pl/wavesoftware/utils/mapstruct/CompositeContext.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@
1717
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
1818
* @since 02.05.18
1919
*/
20-
public final class CompositeMappingContext implements MapstructContext {
20+
public final class CompositeContext implements MapStructContext {
2121
private final List<MappingContext> mappingContexts = new ArrayList<>();
2222

2323
/**
2424
* You can pass multiple mapping contexts to be used in this composite mapping context
2525
*
2626
* @param mappingContexts a array of mapping contexts
2727
*/
28-
public CompositeMappingContext(MappingContext... mappingContexts) {
28+
public CompositeContext(MappingContext... mappingContexts) {
2929
Collections.addAll(this.mappingContexts, mappingContexts);
3030
}
3131

3232
/**
33-
* A builder interface for {@link CompositeMappingContext}.
33+
* A builder interface for {@link CompositeContext}.
3434
*
3535
* @return a builder interface
3636
*/
37-
public static CompositeMappingContextBuilder builder() {
38-
return new CompositeMappingContextBuilder();
37+
public static CompositeContextBuilder builder() {
38+
return new CompositeContextBuilder();
3939
}
4040

4141
@Override
@@ -71,18 +71,18 @@ public <T> Optional<T> getMappedInstanceOptional(Object source,
7171
return Optional.empty();
7272
}
7373

74-
private static final class CompositeMappingContextBuilder {
74+
public static final class CompositeContextBuilder {
7575
private final List<MappingContext> mappingContexts = new ArrayList<>();
7676

77-
public CompositeMappingContextBuilder addContext(MappingContext... mappingContexts) {
77+
public CompositeContextBuilder addContext(MappingContext... mappingContexts) {
7878
this.mappingContexts.addAll(
7979
Arrays.asList(mappingContexts)
8080
);
8181
return this;
8282
}
8383

84-
public CompositeMappingContext build() {
85-
return new CompositeMappingContext(
84+
public CompositeContext build() {
85+
return new CompositeContext(
8686
mappingContexts.toArray(new MappingContext[0])
8787
);
8888
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
import pl.wavesoftware.utils.mapstruct.lang.TriConsumer;
4+
5+
/**
6+
* @author <a href="krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszyński</a>
7+
* @since 2018-05-02
8+
*/
9+
public abstract class CompositeContextMapping<I, O> extends Mapping<I, O, CompositeContext> {
10+
protected CompositeContextMapping(Class<I> sourceClass,
11+
Class<O> targetClass) {
12+
super(sourceClass, targetClass, CompositeContext.class);
13+
}
14+
15+
public static <I, O> CompositeContextMapping<I, O> mapperFor(Class<I> inputClass,
16+
Class<O> outputClass,
17+
TriConsumer<I, O, CompositeContext> consumer) {
18+
return new CompositeContextMapping<I, O>(inputClass, outputClass) {
19+
@Override
20+
public void accept(I input, O output, CompositeContext context) {
21+
consumer.accept(input, output, context);
22+
}
23+
};
24+
}
25+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
import java.util.Optional;
4+
5+
/**
6+
* Identifier collector is responsible for collecting identifier from object. If it can't
7+
* fetch an identifier it should return {@link Optional#empty()} value.
8+
* <p>
9+
*
10+
* Example:
11+
* <pre>
12+
* final class LongIdentifierCollector implements IdentifierCollector {
13+
* public Optional&lt;Object&gt; getIdentifierFromSource(Object source) {
14+
* if (source instanceof AbstractEntity) {
15+
* return Optional.ofNullable(
16+
* AbstractEntity.class.cast(source).getId()
17+
* );
18+
* }
19+
* return Optional.empty();
20+
* }
21+
* }
22+
* </pre>
23+
*
24+
* @author <a href="krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszyński</a>
25+
* @since 2018-05-02
26+
*/
27+
public interface IdentifierCollector {
28+
/**
29+
* Tries to collect an identifier of source object. An identifier can be any
30+
* object, specific interface is not needed.
31+
*
32+
* @param source a source object to collect identifier from
33+
* @return an optional identifier, if not found {@link Optional#empty()} is returned.
34+
*/
35+
Optional<Object> getIdentifierFromSource(Object source);
36+
}

src/main/java/pl/wavesoftware/utils/mapstruct/MapstructContext.java renamed to src/main/java/pl/wavesoftware/utils/mapstruct/MapStructContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
1010
* @since 02.05.18
1111
*/
12-
public interface MapstructContext extends StoringMappingContext {
12+
public interface MapStructContext extends StoringMappingContext {
1313

1414
/**
1515
* Gets an already mapped instance of targetType for given source object.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
/**
4+
* @author <a href="krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszyński</a>
5+
* @since 2018-05-03
6+
*/
7+
public interface MapStructContextProvider<C extends MapStructContext> {
8+
C createNewContext();
9+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import pl.wavesoftware.utils.mapstruct.lang.TriConsumer;
6+
7+
/**
8+
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
9+
* @since 25.04.18
10+
*/
11+
@Getter
12+
@RequiredArgsConstructor
13+
public abstract class Mapping<I, O, C> implements TriConsumer<I, O, C> {
14+
private final Class<I> sourceClass;
15+
private final Class<O> targetClass;
16+
private final Class<C> contextClass;
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
/**
4+
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
5+
* @since 26.04.18
6+
*/
7+
public interface MappingProvider<I, O, C> {
8+
Mapping<I, O, C> provide();
9+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package pl.wavesoftware.utils.mapstruct;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import pl.wavesoftware.eid.exceptions.Eid;
5+
import pl.wavesoftware.eid.exceptions.EidIllegalStateException;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
/**
11+
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
12+
* @since 25.04.18
13+
*/
14+
public interface Mappings {
15+
<I, O, C> Mapping<I, O, C> getMapping(Class<I> sourceClass,
16+
Class<O> targetClass);
17+
18+
static MappingsBuilder builder() {
19+
return new MappingsBuilderImpl();
20+
}
21+
22+
interface MappingsBuilder {
23+
MappingsBuilder addMapping(Mapping<?, ?, ?> mapping);
24+
Mappings build();
25+
}
26+
27+
final class MappingsBuilderImpl implements MappingsBuilder {
28+
private final List<Mapping<?, ?, ?>> mappings = new ArrayList<>();
29+
30+
@Override
31+
public MappingsBuilder addMapping(Mapping<?, ?, ?> mapping) {
32+
mappings.add(mapping);
33+
return this;
34+
}
35+
36+
@Override
37+
public Mappings build() {
38+
return new MappingsImpl(mappings);
39+
}
40+
41+
@RequiredArgsConstructor
42+
private static final class MappingsImpl implements Mappings {
43+
private final Iterable<Mapping<?, ?, ?>> mappings;
44+
45+
@Override
46+
@SuppressWarnings("unchecked")
47+
public <I, O, C> Mapping<I, O, C> getMapping(Class<I> sourceClass,
48+
Class<O> targetClass) {
49+
for (Mapping<?, ?, ?> mapping : mappings) {
50+
if (mapping.getSourceClass() == sourceClass && mapping.getTargetClass() == targetClass) {
51+
return (Mapping<I, O, C>) mapping;
52+
}
53+
}
54+
throw new EidIllegalStateException(
55+
new Eid("20180425:135245"),
56+
"Mapping for source class %s and target class %s is not configured!",
57+
sourceClass.getName(), targetClass.getName()
58+
);
59+
}
60+
}
61+
}
62+
63+
}

0 commit comments

Comments
 (0)