Skip to content

Commit d688944

Browse files
committed
Implement UUID representation specification
JAVA-3516
1 parent 9d17bea commit d688944

File tree

61 files changed

+2218
-284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2218
-284
lines changed

bson/src/main/org/bson/UuidRepresentation.java

+8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
* @since 3.0
2525
*/
2626
public enum UuidRepresentation {
27+
28+
/**
29+
* An unspecified representation of UUID. Essentially, this is the null representation value.
30+
*
31+
* @since 3.12
32+
*/
33+
UNSPECIFIED,
34+
2735
/**
2836
* The canonical representation of UUID
2937
*

bson/src/main/org/bson/codecs/DocumentCodec.java

+39-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.bson.codecs;
1818

19-
import org.bson.BsonBinarySubType;
2019
import org.bson.BsonDocument;
2120
import org.bson.BsonDocumentWriter;
2221
import org.bson.BsonReader;
@@ -25,6 +24,7 @@
2524
import org.bson.BsonWriter;
2625
import org.bson.Document;
2726
import org.bson.Transformer;
27+
import org.bson.UuidRepresentation;
2828
import org.bson.codecs.configuration.CodecRegistry;
2929

3030
import java.util.ArrayList;
@@ -42,7 +42,7 @@
4242
* @see org.bson.Document
4343
* @since 3.0
4444
*/
45-
public class DocumentCodec implements CollectibleCodec<Document> {
45+
public class DocumentCodec implements CollectibleCodec<Document>, OverridableUuidRepresentationCodec<Document> {
4646

4747
private static final String ID_FIELD_NAME = "_id";
4848
private static final CodecRegistry DEFAULT_REGISTRY = fromProviders(asList(new ValueCodecProvider(),
@@ -54,6 +54,7 @@ public class DocumentCodec implements CollectibleCodec<Document> {
5454
private final CodecRegistry registry;
5555
private final IdGenerator idGenerator;
5656
private final Transformer valueTransformer;
57+
private final UuidRepresentation uuidRepresentation;
5758

5859
/**
5960
* Construct a new instance with a default {@code CodecRegistry}.
@@ -92,15 +93,27 @@ public DocumentCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTy
9293
* @param valueTransformer the value transformer to use as a final step when decoding the value of any field in the document
9394
*/
9495
public DocumentCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTypeClassMap, final Transformer valueTransformer) {
96+
this(registry, new BsonTypeCodecMap(notNull("bsonTypeClassMap", bsonTypeClassMap), registry),
97+
new ObjectIdGenerator(), valueTransformer, UuidRepresentation.JAVA_LEGACY);
98+
}
99+
100+
private DocumentCodec(final CodecRegistry registry, final BsonTypeCodecMap bsonTypeCodecMap, final IdGenerator idGenerator,
101+
final Transformer valueTransformer, final UuidRepresentation uuidRepresentation) {
95102
this.registry = notNull("registry", registry);
96-
this.bsonTypeCodecMap = new BsonTypeCodecMap(notNull("bsonTypeClassMap", bsonTypeClassMap), registry);
97-
this.idGenerator = new ObjectIdGenerator();
103+
this.bsonTypeCodecMap = bsonTypeCodecMap;
104+
this.idGenerator = idGenerator;
98105
this.valueTransformer = valueTransformer != null ? valueTransformer : new Transformer() {
99106
@Override
100107
public Object transform(final Object value) {
101108
return value;
102109
}
103110
};
111+
this.uuidRepresentation = uuidRepresentation;
112+
}
113+
114+
@Override
115+
public Codec<Document> withUuidRepresentation(final UuidRepresentation uuidRepresentation) {
116+
return new DocumentCodec(registry, bsonTypeCodecMap, idGenerator, valueTransformer, uuidRepresentation);
104117
}
105118

106119
@Override
@@ -216,10 +229,29 @@ private Object readValue(final BsonReader reader, final DecoderContext decoderCo
216229
return null;
217230
} else if (bsonType == BsonType.ARRAY) {
218231
return readList(reader, decoderContext);
219-
} else if (bsonType == BsonType.BINARY && BsonBinarySubType.isUuid(reader.peekBinarySubType()) && reader.peekBinarySize() == 16) {
220-
return registry.get(UUID.class).decode(reader, decoderContext);
232+
} else {
233+
Codec<?> codec = bsonTypeCodecMap.get(bsonType);
234+
235+
if (bsonType == BsonType.BINARY && reader.peekBinarySize() == 16) {
236+
switch (reader.peekBinarySubType()) {
237+
case 3:
238+
if (uuidRepresentation == UuidRepresentation.JAVA_LEGACY
239+
|| uuidRepresentation == UuidRepresentation.C_SHARP_LEGACY
240+
|| uuidRepresentation == UuidRepresentation.PYTHON_LEGACY) {
241+
codec = registry.get(UUID.class);
242+
}
243+
break;
244+
case 4:
245+
if (uuidRepresentation == UuidRepresentation.JAVA_LEGACY || uuidRepresentation == UuidRepresentation.STANDARD) {
246+
codec = registry.get(UUID.class);
247+
}
248+
break;
249+
default:
250+
break;
251+
}
252+
}
253+
return valueTransformer.transform(codec.decode(reader, decoderContext));
221254
}
222-
return valueTransformer.transform(bsonTypeCodecMap.get(bsonType).decode(reader, decoderContext));
223255
}
224256

225257
private List<Object> readList(final BsonReader reader, final DecoderContext decoderContext) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.bson.codecs;
18+
19+
import org.bson.UuidRepresentation;
20+
21+
/**
22+
* A marker interface for {@code Codec} implementations that can derive a new instance that overrides the {@code UuidRepresentation}.
23+
* @param <T> the value type
24+
* @since 3.12
25+
*/
26+
public interface OverridableUuidRepresentationCodec<T> {
27+
/**
28+
* Implementations must return a new instance with the {@code UuidRepresentation} overridden with the given value.
29+
*
30+
* @param uuidRepresentation the UuidRepresentation
31+
* @return a new instance equivalent to this but with the given UuidRepresentation
32+
*/
33+
Codec<T> withUuidRepresentation(UuidRepresentation uuidRepresentation);
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.bson.codecs;
18+
19+
import org.bson.UuidRepresentation;
20+
21+
import java.util.UUID;
22+
23+
/**
24+
* An extension of {@code UuidCodec} that allows its configured {@code UuidRepresentation} to be overridden by an externally configured
25+
* {@code UuidRepresentation}, most likely configured on {@code MongoClientSettings} or {@code MongoClientOptions}.
26+
*
27+
* @since 3.12
28+
*/
29+
public class OverridableUuidRepresentationUuidCodec extends UuidCodec implements OverridableUuidRepresentationCodec<UUID> {
30+
31+
/**
32+
* Construct an instance with the default UUID representation.
33+
*/
34+
public OverridableUuidRepresentationUuidCodec() {
35+
}
36+
37+
/**
38+
* Construct an instance with the given UUID representation.
39+
*
40+
* @param uuidRepresentation the UUID representation
41+
*/
42+
public OverridableUuidRepresentationUuidCodec(final UuidRepresentation uuidRepresentation) {
43+
super(uuidRepresentation);
44+
}
45+
46+
@Override
47+
public Codec<UUID> withUuidRepresentation(final UuidRepresentation uuidRepresentation) {
48+
return new OverridableUuidRepresentationUuidCodec(uuidRepresentation);
49+
}
50+
}

bson/src/main/org/bson/codecs/UuidCodec.java

+30-10
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@
2222
import org.bson.BsonReader;
2323
import org.bson.BsonWriter;
2424
import org.bson.UuidRepresentation;
25-
25+
import org.bson.codecs.configuration.CodecConfigurationException;
2626
import org.bson.internal.UuidHelper;
2727

2828
import java.util.UUID;
2929

30+
import static org.bson.assertions.Assertions.notNull;
31+
3032
/**
3133
* Encodes and decodes {@code UUID} objects.
3234
*
3335
* @since 3.0
3436
*/
3537
public class UuidCodec implements Codec<UUID> {
3638

37-
private final UuidRepresentation encoderUuidRepresentation;
38-
private final UuidRepresentation decoderUuidRepresentation;
39+
private final UuidRepresentation uuidRepresentation;
3940

4041
/**
4142
* The default UUIDRepresentation is JAVA_LEGACY to be compatible with existing documents
@@ -44,23 +45,35 @@ public class UuidCodec implements Codec<UUID> {
4445
* @see org.bson.UuidRepresentation
4546
*/
4647
public UuidCodec(final UuidRepresentation uuidRepresentation) {
47-
this.encoderUuidRepresentation = uuidRepresentation;
48-
this.decoderUuidRepresentation = uuidRepresentation;
48+
notNull("uuidRepresentation", uuidRepresentation);
49+
this.uuidRepresentation = uuidRepresentation;
4950
}
5051

5152
/**
5253
* The constructor for UUIDCodec, default is JAVA_LEGACY
5354
*/
5455
public UuidCodec() {
55-
this.encoderUuidRepresentation = UuidRepresentation.JAVA_LEGACY;
56-
this.decoderUuidRepresentation = UuidRepresentation.JAVA_LEGACY;
56+
this.uuidRepresentation = UuidRepresentation.JAVA_LEGACY;
57+
}
58+
59+
/**
60+
* The {@code UuidRepresentation} with which this instance is configured
61+
*
62+
* @return the uuid representation
63+
* @since 3.12
64+
*/
65+
public UuidRepresentation getUuidRepresentation() {
66+
return uuidRepresentation;
5767
}
5868

5969
@Override
6070
public void encode(final BsonWriter writer, final UUID value, final EncoderContext encoderContext) {
61-
byte[] binaryData = UuidHelper.encodeUuidToBinary(value, encoderUuidRepresentation);
71+
if (uuidRepresentation == UuidRepresentation.UNSPECIFIED) {
72+
throw new CodecConfigurationException("The uuidRepresentation has not been specified, so the UUID cannot be encoded.");
73+
}
74+
byte[] binaryData = UuidHelper.encodeUuidToBinary(value, uuidRepresentation);
6275
// changed the default subtype to STANDARD since 3.0
63-
if (encoderUuidRepresentation == UuidRepresentation.STANDARD) {
76+
if (uuidRepresentation == UuidRepresentation.STANDARD) {
6477
writer.writeBinaryData(new BsonBinary(BsonBinarySubType.UUID_STANDARD, binaryData));
6578
} else {
6679
writer.writeBinaryData(new BsonBinary(BsonBinarySubType.UUID_LEGACY, binaryData));
@@ -77,11 +90,18 @@ public UUID decode(final BsonReader reader, final DecoderContext decoderContext)
7790

7891
byte[] bytes = reader.readBinaryData().getData();
7992

80-
return UuidHelper.decodeBinaryToUuid(bytes, subType, decoderUuidRepresentation);
93+
return UuidHelper.decodeBinaryToUuid(bytes, subType, uuidRepresentation);
8194
}
8295

8396
@Override
8497
public Class<UUID> getEncoderClass() {
8598
return UUID.class;
8699
}
100+
101+
@Override
102+
public String toString() {
103+
return "UuidCodec{"
104+
+ "uuidRepresentation=" + uuidRepresentation
105+
+ '}';
106+
}
87107
}

bson/src/main/org/bson/codecs/ValueCodecProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ private void addCodecs() {
8585
addCodec(new CharacterCodec());
8686
addCodec(new StringCodec());
8787
addCodec(new SymbolCodec());
88-
addCodec(new UuidCodec());
88+
addCodec(new OverridableUuidRepresentationUuidCodec());
8989

9090
addCodec(new ByteCodec());
9191
addCodec(new PatternCodec());

bson/src/main/org/bson/codecs/configuration/CodecRegistries.java

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.bson.codecs.configuration;
1818

1919
import org.bson.codecs.Codec;
20+
import org.bson.internal.ProvidersCodecRegistry;
2021

2122
import java.util.ArrayList;
2223
import java.util.List;

bson/src/main/org/bson/codecs/configuration/ChildCodecRegistry.java renamed to bson/src/main/org/bson/internal/ChildCodecRegistry.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.bson.codecs.configuration;
17+
package org.bson.internal;
1818

1919

2020
import org.bson.codecs.Codec;
21+
import org.bson.codecs.configuration.CodecRegistry;
2122

2223
// An implementation of CodecRegistry that is used to detect cyclic dependencies between Codecs
2324
class ChildCodecRegistry<T> implements CodecRegistry {
2425

2526
private final ChildCodecRegistry<?> parent;
26-
private final ProvidersCodecRegistry registry;
27+
private final CycleDetectingCodecRegistry registry;
2728
private final Class<T> codecClass;
2829

29-
ChildCodecRegistry(final ProvidersCodecRegistry registry, final Class<T> codecClass) {
30+
ChildCodecRegistry(final CycleDetectingCodecRegistry registry, final Class<T> codecClass) {
3031
this.codecClass = codecClass;
3132
this.parent = null;
3233
this.registry = registry;

bson/src/main/org/bson/codecs/configuration/CodecCache.java renamed to bson/src/main/org/bson/internal/CodecCache.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.bson.codecs.configuration;
17+
package org.bson.internal;
1818

1919
import org.bson.codecs.Codec;
20+
import org.bson.codecs.configuration.CodecConfigurationException;
2021

2122
import java.util.concurrent.ConcurrentHashMap;
2223
import java.util.concurrent.ConcurrentMap;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.bson.internal;
18+
19+
import org.bson.UuidRepresentation;
20+
import org.bson.codecs.configuration.CodecConfigurationException;
21+
import org.bson.codecs.configuration.CodecProvider;
22+
import org.bson.codecs.configuration.CodecRegistry;
23+
24+
public final class CodecRegistryHelper {
25+
26+
public static CodecRegistry createRegistry(final CodecRegistry codecRegistry, final UuidRepresentation uuidRepresentation) {
27+
CodecRegistry retVal = codecRegistry;
28+
if (uuidRepresentation != UuidRepresentation.JAVA_LEGACY) {
29+
if (codecRegistry instanceof CodecProvider) {
30+
retVal = new OverridableUuidRepresentationCodecRegistry((CodecProvider) codecRegistry, uuidRepresentation);
31+
} else {
32+
throw new CodecConfigurationException("Changing the default UuidRepresentation requires a CodecRegistry that also "
33+
+ "implements the CodecProvider interface");
34+
}
35+
}
36+
return retVal;
37+
}
38+
39+
private CodecRegistryHelper() {
40+
}
41+
}

0 commit comments

Comments
 (0)