Skip to content

Commit 41f8cf0

Browse files
visualagerozza
authored andcommitted
Allow discriminators to be used in a collection.
Fixes encoding issue, so that actual codecs for interfaces or abstract classes are used. JAVA-2608
1 parent b376aa4 commit 41f8cf0

File tree

6 files changed

+297
-23
lines changed

6 files changed

+297
-23
lines changed

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

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,34 @@ final class PojoCodecImpl<T> extends PojoCodec<T> {
6969
}
7070
}
7171

72+
@SuppressWarnings("unchecked")
7273
@Override
7374
public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) {
7475
if (!specialized) {
7576
throw new CodecConfigurationException(format("%s contains generic types that have not been specialised.%n"
7677
+ "Top level classes with generic types are not supported by the PojoCodec.", classModel.getName()));
7778
}
78-
writer.writeStartDocument();
79-
PropertyModel<?> idPropertyModel = classModel.getIdPropertyModel();
80-
if (idPropertyModel != null) {
81-
encodeProperty(writer, value, encoderContext, idPropertyModel);
82-
}
79+
if (areEquivalentTypes(value.getClass(), classModel.getType())) {
80+
writer.writeStartDocument();
81+
PropertyModel<?> idPropertyModel = classModel.getIdPropertyModel();
82+
if (idPropertyModel != null) {
83+
encodeProperty(writer, value, encoderContext, idPropertyModel);
84+
}
8385

84-
if (classModel.useDiscriminator()) {
85-
writer.writeString(classModel.getDiscriminatorKey(), classModel.getDiscriminator());
86-
}
86+
if (classModel.useDiscriminator()) {
87+
writer.writeString(classModel.getDiscriminatorKey(), classModel.getDiscriminator());
88+
}
8789

88-
for (PropertyModel<?> propertyModel : classModel.getPropertyModels()) {
89-
if (propertyModel.equals(classModel.getIdPropertyModel())) {
90-
continue;
90+
for (PropertyModel<?> propertyModel : classModel.getPropertyModels()) {
91+
if (propertyModel.equals(classModel.getIdPropertyModel())) {
92+
continue;
93+
}
94+
encodeProperty(writer, value, encoderContext, propertyModel);
9195
}
92-
encodeProperty(writer, value, encoderContext, propertyModel);
96+
writer.writeEndDocument();
97+
} else {
98+
((Codec<T>) registry.get(value.getClass())).encode(writer, value, encoderContext);
9399
}
94-
writer.writeEndDocument();
95100
}
96101

97102
@Override
@@ -134,7 +139,7 @@ private <S> void encodeProperty(final BsonWriter writer, final T instance, final
134139
if (propertyValue == null) {
135140
writer.writeNull();
136141
} else {
137-
getInstanceCodec(propertyModel, propertyValue.getClass()).encode(writer, propertyValue, encoderContext);
142+
propertyModel.getCachedCodec().encode(writer, propertyValue, encoderContext);
138143
}
139144
}
140145
}
@@ -210,15 +215,6 @@ private <S> Codec<S> getCodecFromTypeData(final TypeData<S> typeData) {
210215
return codec;
211216
}
212217

213-
@SuppressWarnings("unchecked")
214-
private <S, V> Codec<S> getInstanceCodec(final PropertyModel<S> propertyModel, final Class<V> instanceType) {
215-
Codec<S> codec = propertyModel.getCachedCodec();
216-
if (!areEquivalentTypes(codec.getEncoderClass(), instanceType)) {
217-
codec = (Codec<S>) registry.get(instanceType);
218-
}
219-
return codec;
220-
}
221-
222218
private <S, V> boolean areEquivalentTypes(final Class<S> t1, final Class<V> t2) {
223219
if (t1.equals(t2)) {
224220
return true;

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,25 @@
5454
import org.bson.codecs.pojo.entities.SimpleModel;
5555
import org.bson.codecs.pojo.entities.SimpleNestedPojoModel;
5656
import org.bson.codecs.pojo.entities.UpperBoundsConcreteModel;
57+
import org.bson.codecs.pojo.entities.conventions.CollectionDiscriminatorModel;
5758
import org.bson.codecs.pojo.entities.conventions.CreatorAllFinalFieldsModel;
5859
import org.bson.codecs.pojo.entities.conventions.CreatorConstructorIdModel;
5960
import org.bson.codecs.pojo.entities.conventions.CreatorConstructorModel;
6061
import org.bson.codecs.pojo.entities.conventions.CreatorConstructorRenameModel;
6162
import org.bson.codecs.pojo.entities.conventions.CreatorMethodModel;
6263
import org.bson.codecs.pojo.entities.conventions.CreatorNoArgsConstructorModel;
6364
import org.bson.codecs.pojo.entities.conventions.CreatorNoArgsMethodModel;
65+
import org.bson.codecs.pojo.entities.conventions.Subclass1Model;
66+
import org.bson.codecs.pojo.entities.conventions.Subclass2Model;
67+
import org.bson.codecs.pojo.entities.conventions.SuperClassModel;
6468
import org.junit.Test;
6569
import org.junit.runner.RunWith;
6670
import org.junit.runners.Parameterized;
6771

6872
import java.util.ArrayList;
73+
import java.util.Arrays;
6974
import java.util.Collection;
75+
import java.util.Collections;
7076
import java.util.List;
7177

7278
import static java.lang.String.format;
@@ -271,6 +277,16 @@ private static List<TestData> testCases() {
271277
getPojoCodecProviderBuilder(ContainsAlternativeMapAndCollectionModel.class),
272278
"{customList: [1,2,3], customMap: {'field': 'value'}}"));
273279

280+
data.add(new TestData("Collection of discriminators", new CollectionDiscriminatorModel().setList(Arrays
281+
.asList(new Subclass1Model().setName("abc").setValue(true),
282+
new Subclass2Model().setInteger(234).setValue(false))).setMap(
283+
Collections.singletonMap("key", new Subclass2Model().setInteger(123).setValue(true))),
284+
getPojoCodecProviderBuilder(CollectionDiscriminatorModel.class, SuperClassModel.class, Subclass1Model.class,
285+
Subclass2Model.class),
286+
"{list: [{_t: 'org.bson.codecs.pojo.entities.conventions.Subclass1Model', value: true, name: 'abc'},"
287+
+ "{_t: 'org.bson.codecs.pojo.entities.conventions.Subclass2Model', value: false, integer: 234}],"
288+
+ "map: {key: {_t: 'org.bson.codecs.pojo.entities.conventions.Subclass2Model', value: true, integer: 123}}}"));
289+
274290
return data;
275291
}
276292

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.conventions;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
public class CollectionDiscriminatorModel {
23+
private List<SuperClassModel> list;
24+
private Map<String, SuperClassModel> map;
25+
26+
public List<SuperClassModel> getList() {
27+
return list;
28+
}
29+
30+
public CollectionDiscriminatorModel setList(final List<SuperClassModel> list) {
31+
this.list = list;
32+
return this;
33+
}
34+
35+
public Map<String, SuperClassModel> getMap() {
36+
return map;
37+
}
38+
39+
public CollectionDiscriminatorModel setMap(final Map<String, SuperClassModel> map) {
40+
this.map = map;
41+
return this;
42+
}
43+
44+
@Override
45+
public boolean equals(final Object o) {
46+
if (this == o) {
47+
return true;
48+
}
49+
if (o == null || getClass() != o.getClass()) {
50+
return false;
51+
}
52+
53+
CollectionDiscriminatorModel that = (CollectionDiscriminatorModel) o;
54+
55+
if (getList() != null ? !getList().equals(that.getList()) : that.getList() != null) {
56+
return false;
57+
}
58+
return getMap() != null ? getMap().equals(that.getMap()) : that.getMap() == null;
59+
}
60+
61+
@Override
62+
public int hashCode() {
63+
int result = getList() != null ? getList().hashCode() : 0;
64+
result = 31 * result + (getMap() != null ? getMap().hashCode() : 0);
65+
return result;
66+
}
67+
68+
@Override
69+
public String toString() {
70+
return "CollectionDiscriminatorModel{"
71+
+ "list=" + list
72+
+ ", map=" + map
73+
+ '}';
74+
}
75+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.conventions;
18+
19+
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
20+
21+
@BsonDiscriminator
22+
public class Subclass1Model extends SuperClassModel {
23+
private String name;
24+
25+
public String getName() {
26+
return name;
27+
}
28+
29+
public Subclass1Model setName(final String name) {
30+
this.name = name;
31+
return this;
32+
}
33+
34+
@Override
35+
public boolean equals(final Object o) {
36+
if (this == o) {
37+
return true;
38+
}
39+
if (o == null || getClass() != o.getClass()) {
40+
return false;
41+
}
42+
if (!super.equals(o)) {
43+
return false;
44+
}
45+
46+
Subclass1Model that = (Subclass1Model) o;
47+
48+
return getName() != null ? getName().equals(that.getName()) : that.getName() == null;
49+
}
50+
51+
@Override
52+
public int hashCode() {
53+
int result = super.hashCode();
54+
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
55+
return result;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return "Subclass1Model{"
61+
+ "name='" + name + '\''
62+
+ "} " + super.toString();
63+
}
64+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.conventions;
18+
19+
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
20+
21+
@BsonDiscriminator
22+
public class Subclass2Model extends SuperClassModel {
23+
private int integer;
24+
25+
public int getInteger() {
26+
return integer;
27+
}
28+
29+
public Subclass2Model setInteger(final int integer) {
30+
this.integer = integer;
31+
return this;
32+
}
33+
34+
@Override
35+
public boolean equals(final Object o) {
36+
if (this == o) {
37+
return true;
38+
}
39+
if (o == null || getClass() != o.getClass()) {
40+
return false;
41+
}
42+
if (!super.equals(o)) {
43+
return false;
44+
}
45+
46+
Subclass2Model that = (Subclass2Model) o;
47+
48+
return getInteger() == that.getInteger();
49+
}
50+
51+
@Override
52+
public int hashCode() {
53+
int result = super.hashCode();
54+
result = 31 * result + getInteger();
55+
return result;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return "Subclass2Model{"
61+
+ "integer=" + integer
62+
+ "} " + super.toString();
63+
}
64+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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.conventions;
18+
19+
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
20+
21+
@BsonDiscriminator
22+
public abstract class SuperClassModel {
23+
private boolean value;
24+
25+
public boolean isValue() {
26+
return value;
27+
}
28+
29+
public SuperClassModel setValue(final boolean value) {
30+
this.value = value;
31+
return this;
32+
}
33+
34+
@Override
35+
public boolean equals(final Object o) {
36+
if (this == o) {
37+
return true;
38+
}
39+
if (o == null || getClass() != o.getClass()) {
40+
return false;
41+
}
42+
43+
SuperClassModel that = (SuperClassModel) o;
44+
45+
return isValue() == that.isValue();
46+
}
47+
48+
@Override
49+
public int hashCode() {
50+
return (isValue() ? 1 : 0);
51+
}
52+
53+
@Override
54+
public String toString() {
55+
return "SuperClassModel{"
56+
+ "value=" + value
57+
+ '}';
58+
}
59+
}

0 commit comments

Comments
 (0)