3
3
import java .net .InetAddress ;
4
4
import java .net .URI ;
5
5
import java .net .URL ;
6
+ import java .util .ArrayList ;
6
7
import java .util .Arrays ;
7
8
import java .util .Collection ;
9
+ import java .util .Collections ;
8
10
import java .util .HashSet ;
11
+ import java .util .List ;
9
12
import java .util .Set ;
10
13
import java .util .UUID ;
14
+ import java .util .function .Consumer ;
15
+ import java .util .stream .Stream ;
11
16
17
+ import org .springframework .core .convert .converter .Converter ;
18
+ import org .springframework .data .convert .ReadingConverter ;
19
+ import org .springframework .data .convert .WritingConverter ;
20
+ import org .springframework .data .geo .Box ;
21
+ import org .springframework .data .geo .Circle ;
22
+ import org .springframework .data .geo .Point ;
23
+ import org .springframework .data .geo .Polygon ;
12
24
import org .springframework .data .mapping .model .SimpleTypeHolder ;
13
25
import org .springframework .data .relational .core .dialect .ArrayColumns ;
14
26
import org .springframework .data .util .Lazy ;
27
+ import org .springframework .lang .NonNull ;
15
28
import org .springframework .r2dbc .core .binding .BindMarkersFactory ;
16
29
import org .springframework .util .ClassUtils ;
17
30
@@ -25,15 +38,25 @@ public class PostgresDialect extends org.springframework.data.relational.core.di
25
38
26
39
private static final Set <Class <?>> SIMPLE_TYPES ;
27
40
41
+ private static final boolean GEO_TYPES_PRESENT = ClassUtils .isPresent ("io.r2dbc.postgresql.codec.Polygon" ,
42
+ PostgresDialect .class .getClassLoader ());
43
+
28
44
static {
29
45
30
46
Set <Class <?>> simpleTypes = new HashSet <>(Arrays .asList (UUID .class , URL .class , URI .class , InetAddress .class ));
31
47
32
- if (ClassUtils .isPresent ("io.r2dbc.postgresql.codec.Json" , PostgresDialect .class .getClassLoader ())) {
48
+ // conditional Postgres JSON support.
49
+ ifClassPresent ("io.r2dbc.postgresql.codec.Json" , simpleTypes ::add );
33
50
34
- simpleTypes
35
- .add (ClassUtils .resolveClassName ("io.r2dbc.postgresql.codec.Json" , PostgresDialect .class .getClassLoader ()));
36
- }
51
+ // conditional Postgres Geo support.
52
+ Stream .of ("io.r2dbc.postgresql.codec.Box" , //
53
+ "io.r2dbc.postgresql.codec.Circle" , //
54
+ "io.r2dbc.postgresql.codec.Line" , //
55
+ "io.r2dbc.postgresql.codec.Lseg" , //
56
+ "io.r2dbc.postgresql.codec.Point" , //
57
+ "io.r2dbc.postgresql.codec.Path" , //
58
+ "io.r2dbc.postgresql.codec.Polygon" ) //
59
+ .forEach (s -> ifClassPresent (s , simpleTypes ::add ));
37
60
38
61
SIMPLE_TYPES = simpleTypes ;
39
62
}
@@ -76,6 +99,23 @@ public ArrayColumns getArraySupport() {
76
99
return this .arrayColumns .get ();
77
100
}
78
101
102
+ /*
103
+ * (non-Javadoc)
104
+ * @see org.springframework.data.r2dbc.dialect.Dialect#getConverters()
105
+ */
106
+ @ Override
107
+ public Collection <Object > getConverters () {
108
+
109
+ if (GEO_TYPES_PRESENT ) {
110
+ return Arrays .asList (FromPostgresPointConverter .INSTANCE , ToPostgresPointConverter .INSTANCE , //
111
+ FromPostgresCircleConverter .INSTANCE , ToPostgresCircleConverter .INSTANCE , //
112
+ FromPostgresBoxConverter .INSTANCE , ToPostgresBoxConverter .INSTANCE , //
113
+ FromPostgresPolygonConverter .INSTANCE , ToPostgresPolygonConverter .INSTANCE );
114
+ }
115
+
116
+ return Collections .emptyList ();
117
+ }
118
+
79
119
private static class R2dbcArrayColumns implements ArrayColumns {
80
120
81
121
private final ArrayColumns delegate ;
@@ -107,4 +147,126 @@ public Class<?> getArrayType(Class<?> userType) {
107
147
}
108
148
}
109
149
150
+ /**
151
+ * If the class is present on the class path, invoke the specified consumer {@code action} with the class object,
152
+ * otherwise do nothing.
153
+ *
154
+ * @param action block to be executed if a value is present.
155
+ */
156
+ private static void ifClassPresent (String className , Consumer <Class <?>> action ) {
157
+
158
+ if (ClassUtils .isPresent (className , PostgresDialect .class .getClassLoader ())) {
159
+ action .accept (ClassUtils .resolveClassName (className , PostgresDialect .class .getClassLoader ()));
160
+ }
161
+ }
162
+
163
+ @ ReadingConverter
164
+ private enum FromPostgresBoxConverter implements Converter <io .r2dbc .postgresql .codec .Box , Box > {
165
+
166
+ INSTANCE ;
167
+
168
+ @ Override
169
+ public Box convert (io .r2dbc .postgresql .codec .Box source ) {
170
+ return new Box (FromPostgresPointConverter .INSTANCE .convert (source .getA ()),
171
+ FromPostgresPointConverter .INSTANCE .convert (source .getB ()));
172
+ }
173
+ }
174
+
175
+ @ WritingConverter
176
+ private enum ToPostgresBoxConverter implements Converter <Box , io .r2dbc .postgresql .codec .Box > {
177
+
178
+ INSTANCE ;
179
+
180
+ @ Override
181
+ public io .r2dbc .postgresql .codec .Box convert (Box source ) {
182
+ return io .r2dbc .postgresql .codec .Box .of (ToPostgresPointConverter .INSTANCE .convert (source .getFirst ()),
183
+ ToPostgresPointConverter .INSTANCE .convert (source .getSecond ()));
184
+ }
185
+ }
186
+
187
+ @ ReadingConverter
188
+ private enum FromPostgresCircleConverter implements Converter <io .r2dbc .postgresql .codec .Circle , Circle > {
189
+
190
+ INSTANCE ;
191
+
192
+ @ Override
193
+ public Circle convert (io .r2dbc .postgresql .codec .Circle source ) {
194
+ return new Circle (source .getCenter ().getX (), source .getCenter ().getY (), source .getRadius ());
195
+ }
196
+ }
197
+
198
+ @ WritingConverter
199
+ private enum ToPostgresCircleConverter implements Converter <Circle , io .r2dbc .postgresql .codec .Circle > {
200
+
201
+ INSTANCE ;
202
+
203
+ @ Override
204
+ public io .r2dbc .postgresql .codec .Circle convert (Circle source ) {
205
+ return io .r2dbc .postgresql .codec .Circle .of (source .getCenter ().getX (), source .getCenter ().getY (),
206
+ source .getRadius ().getValue ());
207
+ }
208
+ }
209
+
210
+ @ ReadingConverter
211
+ private enum FromPostgresPolygonConverter implements Converter <io .r2dbc .postgresql .codec .Polygon , Polygon > {
212
+
213
+ INSTANCE ;
214
+
215
+ @ Override
216
+ public Polygon convert (io .r2dbc .postgresql .codec .Polygon source ) {
217
+
218
+ List <io .r2dbc .postgresql .codec .Point > sourcePoints = source .getPoints ();
219
+ List <Point > targetPoints = new ArrayList <>(sourcePoints .size ());
220
+
221
+ for (io .r2dbc .postgresql .codec .Point sourcePoint : sourcePoints ) {
222
+ targetPoints .add (FromPostgresPointConverter .INSTANCE .convert (sourcePoint ));
223
+ }
224
+
225
+ return new Polygon (targetPoints );
226
+ }
227
+ }
228
+
229
+ @ WritingConverter
230
+ private enum ToPostgresPolygonConverter implements Converter <Polygon , io .r2dbc .postgresql .codec .Polygon > {
231
+
232
+ INSTANCE ;
233
+
234
+ @ Override
235
+ public io .r2dbc .postgresql .codec .Polygon convert (Polygon source ) {
236
+
237
+ List <Point > sourcePoints = source .getPoints ();
238
+ List <io .r2dbc .postgresql .codec .Point > targetPoints = new ArrayList <>(sourcePoints .size ());
239
+
240
+ for (Point sourcePoint : sourcePoints ) {
241
+ targetPoints .add (ToPostgresPointConverter .INSTANCE .convert (sourcePoint ));
242
+ }
243
+
244
+ return io .r2dbc .postgresql .codec .Polygon .of (targetPoints );
245
+ }
246
+ }
247
+
248
+ @ ReadingConverter
249
+ private enum FromPostgresPointConverter implements Converter <io .r2dbc .postgresql .codec .Point , Point > {
250
+
251
+ INSTANCE ;
252
+
253
+ @ Override
254
+ @ NonNull
255
+ public Point convert (io .r2dbc .postgresql .codec .Point source ) {
256
+ return new Point (source .getX (), source .getY ());
257
+ }
258
+ }
259
+
260
+ @ WritingConverter
261
+ private enum ToPostgresPointConverter implements Converter <Point , io .r2dbc .postgresql .codec .Point > {
262
+
263
+ INSTANCE ;
264
+
265
+ @ Override
266
+ @ NonNull
267
+ public io .r2dbc .postgresql .codec .Point convert (Point source ) {
268
+ return io .r2dbc .postgresql .codec .Point .of (source .getX (), source .getY ());
269
+ }
270
+ }
271
+
110
272
}
0 commit comments