Skip to content

Commit befbea5

Browse files
committed
Added Enum support for POJOs
JAVA-268
1 parent 4958094 commit befbea5

File tree

7 files changed

+228
-0
lines changed

7 files changed

+228
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2017 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.pojo;
18+
19+
import org.bson.BsonReader;
20+
import org.bson.BsonWriter;
21+
import org.bson.codecs.Codec;
22+
import org.bson.codecs.DecoderContext;
23+
import org.bson.codecs.EncoderContext;
24+
25+
final class EnumCodec<T extends Enum<T>> implements Codec<T> {
26+
private final Class<T> clazz;
27+
28+
EnumCodec(final Class<T> clazz) {
29+
this.clazz = clazz;
30+
}
31+
32+
@Override
33+
public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) {
34+
writer.writeString(value.name());
35+
}
36+
37+
@Override
38+
public Class<T> getEncoderClass() {
39+
return clazz;
40+
}
41+
42+
@Override
43+
public T decode(final BsonReader reader, final DecoderContext decoderContext) {
44+
return Enum.valueOf(clazz, reader.readString());
45+
}
46+
}

bson/src/main/org/bson/codecs/pojo/PojoCodec.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,17 @@ private <S> Codec<S> getCodecFromTypeData(final TypeData<S> typeData) {
194194
codec = new CollectionCodec(head, getCodecFromTypeData(typeData.getTypeParameters().get(0)));
195195
} else if (Map.class.isAssignableFrom(head)) {
196196
codec = new MapCodec(head, getCodecFromTypeData(typeData.getTypeParameters().get(1)));
197+
} else if (Enum.class.isAssignableFrom(head)) {
198+
try {
199+
codec = registry.get(head);
200+
} catch (CodecConfigurationException e) {
201+
codec = new EnumCodec((Class<Enum<?>>) head);
202+
}
197203
} else {
198204
codec = getCodecFromClass(head);
199205
}
206+
207+
200208
return codec;
201209
}
202210

bson/src/test/unit/org/bson/codecs/pojo/PojoCodecTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
import org.bson.codecs.pojo.entities.ShapeModelAbstract;
5151
import org.bson.codecs.pojo.entities.ShapeModelCircle;
5252
import org.bson.codecs.pojo.entities.ShapeModelRectangle;
53+
import org.bson.codecs.pojo.entities.SimpleEnum;
54+
import org.bson.codecs.pojo.entities.SimpleEnumModel;
5355
import org.bson.codecs.pojo.entities.SimpleGenericsModel;
5456
import org.bson.codecs.pojo.entities.SimpleModel;
5557
import org.bson.codecs.pojo.entities.SimpleNestedPojoModel;
@@ -66,7 +68,9 @@
6668
import static java.lang.String.format;
6769
import static java.util.Arrays.asList;
6870
import static java.util.Collections.singletonList;
71+
import static org.bson.codecs.configuration.CodecRegistries.fromCodecs;
6972
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
73+
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
7074
import static org.bson.codecs.pojo.Conventions.NO_CONVENTIONS;
7175

7276
public final class PojoCodecTest extends PojoTestCase {
@@ -340,6 +344,20 @@ public void apply(final ClassModelBuilder<?> classModelBuilder) {
340344
+ " 'simple_model': {'integer_field': 42, 'string_field': 'myString' } } }");
341345
}
342346

347+
@Test
348+
public void testEnumSupport() {
349+
SimpleEnumModel model = new SimpleEnumModel(SimpleEnum.BRAVO);
350+
roundTrip(getPojoCodecProviderBuilder(SimpleEnumModel.class), model, "{ 'myEnum': 'BRAVO' }");
351+
}
352+
353+
@Test
354+
public void testEnumSupportWithCustomCodec() {
355+
SimpleEnumModel model = new SimpleEnumModel(SimpleEnum.BRAVO);
356+
CodecRegistry registry = fromRegistries(getCodecRegistry(getPojoCodecProviderBuilder(SimpleEnumModel.class)),
357+
fromCodecs(new SimpleEnumCodec()));
358+
roundTrip(registry, model, "{ 'myEnum': 1 }");
359+
}
360+
343361
@Test
344362
@SuppressWarnings("unchecked")
345363
public void testCustomCodec() {

bson/src/test/unit/org/bson/codecs/pojo/PojoTestCase.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.bson.codecs.pojo.entities.ReusedGenericsModel;
4141
import org.bson.codecs.pojo.entities.ShapeModelCircle;
4242
import org.bson.codecs.pojo.entities.ShapeModelRectangle;
43+
import org.bson.codecs.pojo.entities.SimpleEnum;
4344
import org.bson.codecs.pojo.entities.SimpleGenericsModel;
4445
import org.bson.codecs.pojo.entities.SimpleModel;
4546
import org.bson.codecs.pojo.entities.SimpleNestedPojoModel;
@@ -297,4 +298,30 @@ public String decode(final BsonReader reader, final DecoderContext decoderContex
297298
return reader.readObjectId().toHexString();
298299
}
299300
}
301+
302+
class SimpleEnumCodec implements Codec<SimpleEnum> {
303+
304+
@Override
305+
public void encode(final BsonWriter writer, final SimpleEnum value, final EncoderContext encoderContext) {
306+
writer.writeInt32(value.ordinal());
307+
}
308+
309+
@Override
310+
public Class<SimpleEnum> getEncoderClass() {
311+
return SimpleEnum.class;
312+
}
313+
314+
@Override
315+
public SimpleEnum decode(final BsonReader reader, final DecoderContext decoderContext) {
316+
int ordinal = reader.readInt32();
317+
switch (ordinal){
318+
case 0:
319+
return SimpleEnum.ALPHA;
320+
case 1:
321+
return SimpleEnum.BRAVO;
322+
default:
323+
return SimpleEnum.CHARLIE;
324+
}
325+
}
326+
}
300327
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2017 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.pojo.entities;
18+
19+
public enum SimpleEnum {
20+
ALPHA,
21+
BRAVO,
22+
CHARLIE
23+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2017 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.pojo.entities;
18+
19+
public final class SimpleEnumModel {
20+
21+
private SimpleEnum myEnum;
22+
23+
public SimpleEnumModel() {
24+
}
25+
26+
public SimpleEnumModel(final SimpleEnum myEnum) {
27+
this.myEnum = myEnum;
28+
}
29+
30+
/**
31+
* Returns the myEnum
32+
*
33+
* @return the myEnum
34+
*/
35+
public SimpleEnum getMyEnum() {
36+
return myEnum;
37+
}
38+
39+
/**
40+
* Sets the myEnum
41+
*
42+
* @param myEnum the myEnum
43+
* @return this
44+
*/
45+
public SimpleEnumModel myEnum(final SimpleEnum myEnum) {
46+
this.myEnum = myEnum;
47+
return this;
48+
}
49+
50+
@Override
51+
public boolean equals(final Object o) {
52+
if (this == o) {
53+
return true;
54+
}
55+
if (o == null || getClass() != o.getClass()) {
56+
return false;
57+
}
58+
59+
SimpleEnumModel that = (SimpleEnumModel) o;
60+
61+
if (getMyEnum() != that.getMyEnum()) {
62+
return false;
63+
}
64+
65+
return true;
66+
}
67+
68+
@Override
69+
public int hashCode() {
70+
return getMyEnum() != null ? getMyEnum().hashCode() : 0;
71+
}
72+
}

docs/reference/content/bson/pojos.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,40 @@ serializable because they are bound to the concrete types `Integer`, `String` an
149149
On their own, instances of `GenericTree` or `GenericClass` are not serializable by the `PojoCodec`. This is because the runtime type parameter
150150
information is erased by the JVM, and the type parameters cannot be specialized accurately.
151151

152+
### Enum support
153+
154+
Enums are fully supported. The `PojoCodec` uses the name of the enum constant as the field value. This is then converted back into an Enum
155+
value by the codec using the static `Enum.valueOf` method.
156+
157+
Take the following example:
158+
159+
```Java
160+
161+
public enum Membership {
162+
UNREGISTERED,
163+
SUBSCRIBER,
164+
PREMIUM
165+
}
166+
167+
public class Person {
168+
private String firstName;
169+
private String lastName;
170+
private Member membership = Member.UNREGISTERED;
171+
172+
public Person() { }
173+
174+
public Person(final String firstName, final String lastName, final Membership membership) { }
175+
176+
// Rest of implementation
177+
}
178+
```
179+
180+
The instance of `new Person("Bryan", "May", SUBSCRIBER);` would be serialized to the equivalent of
181+
`{ firstName: "Bryan", lastName: "May", membership: "SUBSCRIBER"}`.
182+
183+
If you require an alternative representation of the Enum, you can override how a Enum is stored by registering a custom `Codec` for the Enum in the `CodecRegistry`.
184+
185+
152186
### Conventions
153187

154188
The [`Convention`]({{<apiref "org/bson/codecs/pojo/Convention.html">}}) interface provides a mechanism for `ClassModelBuilder`

0 commit comments

Comments
 (0)