Skip to content

Commit 19ad9bf

Browse files
committed
ConventionAnnotation updates
Ensure all constuctors are validated. Ignore synthetic and bridge methods when checking for @BsonCreator methods / constructors. JAVA-2688
1 parent 80b935e commit 19ad9bf

File tree

5 files changed

+224
-9
lines changed

5 files changed

+224
-9
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ private <T> void processCreatorAnnotation(final ClassModelBuilder<T> classModelB
102102
Class<T> clazz = classModelBuilder.getType();
103103
CreatorExecutable<T> creatorExecutable = null;
104104
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
105-
if (isPublic(constructor.getModifiers())) {
105+
if (isPublic(constructor.getModifiers()) && !constructor.isSynthetic()) {
106106
for (Annotation annotation : constructor.getDeclaredAnnotations()) {
107107
if (annotation.annotationType().equals(BsonCreator.class)) {
108+
if (creatorExecutable != null) {
109+
throw new CodecConfigurationException("Found multiple constructors annotated with @BsonCreator");
110+
}
108111
creatorExecutable = new CreatorExecutable<T>(clazz, (Constructor<T>) constructor);
109-
break;
110112
}
111113
}
112114
}
@@ -116,7 +118,7 @@ private <T> void processCreatorAnnotation(final ClassModelBuilder<T> classModelB
116118
boolean foundStaticBsonCreatorMethod = false;
117119
while (bsonCreatorClass != null && !foundStaticBsonCreatorMethod) {
118120
for (Method method : bsonCreatorClass.getDeclaredMethods()) {
119-
if (isStatic(method.getModifiers())) {
121+
if (isStatic(method.getModifiers()) && !method.isSynthetic() && !method.isBridge()) {
120122
for (Annotation annotation : method.getDeclaredAnnotations()) {
121123
if (annotation.annotationType().equals(BsonCreator.class)) {
122124
if (creatorExecutable != null) {
@@ -128,7 +130,6 @@ private <T> void processCreatorAnnotation(final ClassModelBuilder<T> classModelB
128130
}
129131
creatorExecutable = new CreatorExecutable<T>(clazz, method);
130132
foundStaticBsonCreatorMethod = true;
131-
break;
132133
}
133134
}
134135
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidMethodModel;
2626
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidMethodReturnTypeModel;
2727
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidMultipleConstructorsModel;
28+
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidMultipleCreatorsModel;
29+
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidMultipleStaticCreatorsModel;
2830
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidTypeConstructorModel;
2931
import org.bson.codecs.pojo.entities.conventions.CreatorInvalidTypeMethodModel;
3032
import org.junit.Test;
@@ -147,6 +149,18 @@ public void testCreatorInvalidMultipleConstructorsModel() {
147149
.conventions(singletonList(ANNOTATION_CONVENTION)).build();
148150
}
149151

152+
@Test(expected = CodecConfigurationException.class)
153+
public void testCreatorInvalidMultipleCreatorsModel() {
154+
ClassModel.builder(CreatorInvalidMultipleCreatorsModel.class)
155+
.conventions(singletonList(ANNOTATION_CONVENTION)).build();
156+
}
157+
158+
@Test(expected = CodecConfigurationException.class)
159+
public void testCreatorInvalidMultipleStaticCreatorsModel() {
160+
ClassModel.builder(CreatorInvalidMultipleStaticCreatorsModel.class)
161+
.conventions(singletonList(ANNOTATION_CONVENTION)).build();
162+
}
163+
150164
@Test(expected = CodecConfigurationException.class)
151165
public void testCreatorInvalidMethodReturnTypeModel() {
152166
ClassModel.builder(CreatorInvalidMethodReturnTypeModel.class)

bson/src/test/unit/org/bson/codecs/pojo/entities/conventions/CreatorInvalidMultipleConstructorsModel.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@ public CreatorInvalidMultipleConstructorsModel(@BsonProperty("integerField") fin
2929
this.integerField = integerField;
3030
}
3131

32+
@BsonCreator
33+
public CreatorInvalidMultipleConstructorsModel(@BsonProperty("integerField") final Integer integerField,
34+
@BsonProperty("stringField") final String string) {
35+
this(integerField);
36+
setStringField(stringField);
37+
}
38+
39+
3240
public CreatorInvalidMultipleConstructorsModel(final Integer integerField, final String stringField, final long longField) {
3341
this.integerField = integerField;
3442
this.stringField = stringField;
3543
this.longField = longField;
3644
}
3745

38-
@BsonCreator
39-
public static CreatorInvalidMultipleConstructorsModel create(@BsonProperty("integerField") final Integer integerField) {
40-
return new CreatorInvalidMultipleConstructorsModel(integerField);
41-
}
42-
4346
public Integer getIntegerField() {
4447
return integerField;
4548
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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.BsonCreator;
20+
import org.bson.codecs.pojo.annotations.BsonProperty;
21+
22+
public final class CreatorInvalidMultipleCreatorsModel {
23+
private final Integer integerField;
24+
private String stringField;
25+
public long longField;
26+
27+
@BsonCreator
28+
public CreatorInvalidMultipleCreatorsModel(@BsonProperty("integerField") final Integer integerField) {
29+
this.integerField = integerField;
30+
}
31+
32+
public CreatorInvalidMultipleCreatorsModel(final Integer integerField, final String stringField, final long longField) {
33+
this.integerField = integerField;
34+
this.stringField = stringField;
35+
this.longField = longField;
36+
}
37+
38+
@BsonCreator
39+
public static CreatorInvalidMultipleCreatorsModel create(@BsonProperty("integerField") final Integer integerField) {
40+
return new CreatorInvalidMultipleCreatorsModel(integerField);
41+
}
42+
43+
public Integer getIntegerField() {
44+
return integerField;
45+
}
46+
47+
public String getStringField() {
48+
return stringField;
49+
}
50+
51+
public void setStringField(final String stringField) {
52+
this.stringField = stringField;
53+
}
54+
55+
@Override
56+
public boolean equals(final Object o) {
57+
if (this == o) {
58+
return true;
59+
}
60+
if (o == null || getClass() != o.getClass()) {
61+
return false;
62+
}
63+
64+
CreatorInvalidMultipleCreatorsModel that = (CreatorInvalidMultipleCreatorsModel) o;
65+
66+
if (longField != that.longField) {
67+
return false;
68+
}
69+
if (getIntegerField() != null ? !getIntegerField().equals(that.getIntegerField()) : that.getIntegerField() != null) {
70+
return false;
71+
}
72+
if (getStringField() != null ? !getStringField().equals(that.getStringField()) : that.getStringField() != null) {
73+
return false;
74+
}
75+
76+
return true;
77+
}
78+
79+
@Override
80+
public int hashCode() {
81+
int result = getIntegerField() != null ? getIntegerField().hashCode() : 0;
82+
result = 31 * result + (getStringField() != null ? getStringField().hashCode() : 0);
83+
result = 31 * result + (int) (longField ^ (longField >>> 32));
84+
return result;
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return "CreatorInvalidMultipleModel{"
90+
+ "integerField=" + integerField
91+
+ ", stringField='" + stringField + "'"
92+
+ ", longField=" + longField
93+
+ "}";
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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.BsonCreator;
20+
import org.bson.codecs.pojo.annotations.BsonProperty;
21+
22+
public final class CreatorInvalidMultipleStaticCreatorsModel {
23+
private final Integer integerField;
24+
private String stringField;
25+
public long longField;
26+
27+
private CreatorInvalidMultipleStaticCreatorsModel(final Integer integerField) {
28+
this.integerField = integerField;
29+
}
30+
31+
public CreatorInvalidMultipleStaticCreatorsModel(final Integer integerField, final String stringField, final long longField) {
32+
this.integerField = integerField;
33+
this.stringField = stringField;
34+
this.longField = longField;
35+
}
36+
37+
@BsonCreator
38+
public static CreatorInvalidMultipleStaticCreatorsModel create(@BsonProperty("integerField") final Integer integerField) {
39+
return new CreatorInvalidMultipleStaticCreatorsModel(integerField);
40+
}
41+
42+
@BsonCreator
43+
public static CreatorInvalidMultipleStaticCreatorsModel create(@BsonProperty("integerField") final Integer integerField,
44+
@BsonProperty("stringField") final String stringField) {
45+
CreatorInvalidMultipleStaticCreatorsModel model = new CreatorInvalidMultipleStaticCreatorsModel(integerField);
46+
model.setStringField(stringField);
47+
return model;
48+
}
49+
50+
public Integer getIntegerField() {
51+
return integerField;
52+
}
53+
54+
public String getStringField() {
55+
return stringField;
56+
}
57+
58+
public void setStringField(final String stringField) {
59+
this.stringField = stringField;
60+
}
61+
62+
@Override
63+
public boolean equals(final Object o) {
64+
if (this == o) {
65+
return true;
66+
}
67+
if (o == null || getClass() != o.getClass()) {
68+
return false;
69+
}
70+
71+
CreatorInvalidMultipleStaticCreatorsModel that = (CreatorInvalidMultipleStaticCreatorsModel) o;
72+
73+
if (longField != that.longField) {
74+
return false;
75+
}
76+
if (getIntegerField() != null ? !getIntegerField().equals(that.getIntegerField()) : that.getIntegerField() != null) {
77+
return false;
78+
}
79+
if (getStringField() != null ? !getStringField().equals(that.getStringField()) : that.getStringField() != null) {
80+
return false;
81+
}
82+
83+
return true;
84+
}
85+
86+
@Override
87+
public int hashCode() {
88+
int result = getIntegerField() != null ? getIntegerField().hashCode() : 0;
89+
result = 31 * result + (getStringField() != null ? getStringField().hashCode() : 0);
90+
result = 31 * result + (int) (longField ^ (longField >>> 32));
91+
return result;
92+
}
93+
94+
@Override
95+
public String toString() {
96+
return "CreatorInvalidMultipleModel{"
97+
+ "integerField=" + integerField
98+
+ ", stringField='" + stringField + "'"
99+
+ ", longField=" + longField
100+
+ "}";
101+
}
102+
}

0 commit comments

Comments
 (0)