Skip to content

Commit b32f92b

Browse files
committed
Merge branch 'master' into support-pre-releases
2 parents 714e4c2 + 85c3165 commit b32f92b

File tree

20 files changed

+391
-59
lines changed

20 files changed

+391
-59
lines changed

.evergreen/.evg.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ functions:
150150
env:
151151
PRODUCT_NAME: ${product_name}
152152
PRODUCT_VERSION: ${product_version}
153+
EVERGREEN_VERSION_ID: ${version_id}
153154
script: .evergreen/ssdlc-report.sh
154155
- command: ec2.assume_role
155156
params:

.evergreen/ssdlc-report.sh

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ set -eu
55
# Supported/used environment variables:
66
# PRODUCT_NAME
77
# PRODUCT_VERSION
8+
# EVERGREEN_VERSION_ID
89

910
if [ -z "${PRODUCT_NAME}" ]; then
10-
echo "PRODUCT_NAME must be set to a non-empty string"
11+
printf "\nPRODUCT_NAME must be set to a non-empty string\n"
1112
exit 1
1213
fi
1314
if [ -z "${PRODUCT_VERSION}" ]; then
14-
echo "PRODUCT_VERSION must be set to a non-empty string"
15+
printf "\nPRODUCT_VERSION must be set to a non-empty string\n"
16+
exit 1
17+
fi
18+
if [ -z "${EVERGREEN_VERSION_ID}" ]; then
19+
printf "\EVERGREEN_VERSION_ID must be set to a non-empty string\n"
1520
exit 1
1621
fi
1722

@@ -22,12 +27,39 @@ RELATIVE_DIR_PATH="$(dirname "${BASH_SOURCE[0]:-$0}")"
2227
source "${RELATIVE_DIR_PATH}/javaConfig.bash"
2328

2429
printf "\nCreating SSDLC reports\n"
30+
printf "\nProduct name: %s\n" "${PRODUCT_NAME}"
31+
printf "\nProduct version: %s\n" "${PRODUCT_VERSION}"
2532

2633
declare -r SSDLC_PATH="${RELATIVE_DIR_PATH}/../build/ssdlc"
2734
declare -r SSDLC_STATIC_ANALYSIS_REPORTS_PATH="${SSDLC_PATH}/static-analysis-reports"
2835
mkdir "${SSDLC_PATH}"
2936
mkdir "${SSDLC_STATIC_ANALYSIS_REPORTS_PATH}"
3037

38+
declare -r EVERGREEN_PROJECT_NAME_PREFIX="${PRODUCT_NAME//-/_}"
39+
declare -r EVERGREEN_BUILD_URL_PREFIX="https://spruce.mongodb.com/version"
40+
declare -r GIT_TAG="r${PRODUCT_VERSION}"
41+
GIT_COMMIT_HASH="$(git rev-list --ignore-missing -n 1 "${GIT_TAG}")"
42+
set +e
43+
GIT_BRANCH_MASTER="$(git branch -a --contains "${GIT_TAG}" | grep 'master$')"
44+
GIT_BRANCH_PATCH="$(git branch -a --contains "${GIT_TAG}" | grep '\.x$')"
45+
set -e
46+
if [ -n "${GIT_BRANCH_MASTER}" ]; then
47+
declare -r EVERGREEN_BUILD_URL="${EVERGREEN_BUILD_URL_PREFIX}/${EVERGREEN_PROJECT_NAME_PREFIX}_${GIT_COMMIT_HASH}"
48+
elif [ -n "${GIT_BRANCH_PATCH}" ]; then
49+
# strip out the patch version
50+
declare -r EVERGREEN_PROJECT_NAME_SUFFIX="${PRODUCT_VERSION%.*}"
51+
declare -r EVERGREEN_BUILD_URL="${EVERGREEN_BUILD_URL_PREFIX}/${EVERGREEN_PROJECT_NAME_PREFIX}_${EVERGREEN_PROJECT_NAME_SUFFIX}_${GIT_COMMIT_HASH}"
52+
elif [[ "${PRODUCT_NAME}" == *'-snapshot' ]]; then
53+
declare -r EVERGREEN_BUILD_URL="${EVERGREEN_BUILD_URL_PREFIX}/${EVERGREEN_VERSION_ID}"
54+
else
55+
printf "\nFailed to compute EVERGREEN_BUILD_URL\n"
56+
exit 1
57+
fi
58+
printf "\nEvergreen build URL: %s\n" "${EVERGREEN_BUILD_URL}"
59+
60+
PRODUCT_RELEASE_CREATOR="$(git log --ignore-missing "${GIT_TAG}"^.."${GIT_TAG}" --simplify-by-decoration --pretty='format:%aN')"
61+
printf "\nProduct release creator: %s\n" "${PRODUCT_RELEASE_CREATOR}"
62+
3163
printf "\nCreating SpotBugs SARIF reports\n"
3264
./gradlew -version
3365
set +e
@@ -52,14 +84,16 @@ declare -r SSDLC_REPORT_PATH="${SSDLC_PATH}/ssdlc_compliance_report.md"
5284
cp "${TEMPLATE_SSDLC_REPORT_PATH}" "${SSDLC_REPORT_PATH}"
5385
declare -a SED_EDIT_IN_PLACE_OPTION
5486
if [[ "$OSTYPE" == "darwin"* ]]; then
55-
SED_EDIT_IN_PLACE_OPTION=(-i '')
87+
SED_EDIT_IN_PLACE_OPTION=(-i '')
5688
else
57-
SED_EDIT_IN_PLACE_OPTION=(-i)
89+
SED_EDIT_IN_PLACE_OPTION=(-i)
5890
fi
5991
sed "${SED_EDIT_IN_PLACE_OPTION[@]}" \
6092
-e "s/\${product_name}/${PRODUCT_NAME}/g" \
6193
-e "s/\${product_version}/${PRODUCT_VERSION}/g" \
6294
-e "s/\${report_date_utc}/$(date -u +%Y-%m-%d)/g" \
95+
-e "s/\${product_release_creator}/${PRODUCT_RELEASE_CREATOR}/g" \
96+
-e "s>\${evergreen_build_url}>${EVERGREEN_BUILD_URL}>g" \
6397
"${SSDLC_REPORT_PATH}"
6498
printf "%s\n" "${SSDLC_REPORT_PATH}"
6599

.evergreen/template_ssdlc_compliance_report.md

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,18 @@ This report is available at
1313
<td>${product_version}</td>
1414
</tr>
1515
<tr>
16-
<th>Report date, UTC</th>
17-
<td>${report_date_utc}</td>
18-
</tr>
19-
</table>
20-
21-
## Release creator
22-
23-
This information is available in multiple ways:
24-
25-
<table>
26-
<tr>
27-
<th>Evergreen</th>
16+
<th>Release creator</th>
2817
<td>
29-
Go to
30-
<a href="https://evergreen.mongodb.com/waterfall/mongo-java-driver?bv_filter=Publish%20Release">
31-
https://evergreen.mongodb.com/waterfall/mongo-java-driver?bv_filter=Publish%20Release</a>,
32-
find the build triggered from Git tag <code>r${product_version}</code>, see who authored it.
18+
${product_release_creator}
19+
<p>
20+
Refer to data in Papertrail for more details.
21+
There is currently no official way to serve that data.
22+
</p>
3323
</td>
3424
</tr>
3525
<tr>
36-
<th>Papertrail</th>
37-
<td>
38-
Refer to data in Papertrail. There is currently no official way to serve that data.
39-
</td>
26+
<th>Report date, UTC</th>
27+
<td>${report_date_utc}</td>
4028
</tr>
4129
</table>
4230

@@ -47,22 +35,31 @@ Blocked on <https://jira.mongodb.org/browse/JAVA-5429>.
4735
The MongoDB SSDLC policy is available at
4836
<https://docs.google.com/document/d/1u0m4Kj2Ny30zU74KoEFCN4L6D_FbEYCaJ3CQdCYXTMc>.
4937

50-
## Third-darty dependency information
38+
## Third-party dependency information
5139

5240
There are no dependencies to report vulnerabilities of.
5341
Our [SBOM](https://docs.devprod.prod.corp.mongodb.com/mms/python/src/sbom/silkbomb/docs/CYCLONEDX/) lite
5442
is <https://github.com/mongodb/mongo-java-driver/blob/r${product_version}/sbom.json>.
5543

5644
## Static analysis findings
5745

58-
The static analysis findings are all available at
46+
The static analysis findings are available at
5947
<https://d-9067613a84.awsapps.com/start/#/console?account_id=857654397073&role_name=Drivers.User&destination=https%3a%2f%2fus-west-1.console.aws.amazon.com%2fs3%2fbuckets%2fjava-driver-release-assets%3fregion%3dus-west-1%26bucketType%3dgeneral%26prefix%3d${product_name}%2f${product_version}%2fstatic-analysis-reports%2f>.
6048
All the findings in the aforementioned reports
6149
are either of the MongoDB status "False Positive" or "No Fix Needed",
6250
because code that has any other findings cannot technically get into the product.
6351

6452
<https://github.com/mongodb/mongo-java-driver/blob/r${product_version}/config/spotbugs/exclude.xml> may also be of interest.
6553

54+
## Security testing results
55+
56+
The testing results are available at
57+
<${evergreen_build_url}>.
58+
59+
See the driver security testing summary
60+
<https://docs.google.com/document/d/1y2K_RY4GZVXpQvv4JH_35mSzFRTawNJ3mibpvSBU8H0>
61+
for the description of what is tested.
62+
6663
## Signature information
6764

6865
The product artifacts are signed.

.github/workflows/release.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ on:
99
required: true
1010
type: "string"
1111

12-
env:
13-
GIT_AUTHOR_EMAIL: "167856002+mongodb-dbx-release-bot[bot]@users.noreply.github.com"
14-
GIT_AUTHOR_NAME: "mongodb-dbx-release-bot[bot]"
15-
1612
jobs:
1713
prepare-release:
1814
environment: release
@@ -90,10 +86,13 @@ jobs:
9086
echo '❌ Release failed due to branch mismatch: expected ${{ inputs.version }} to be released from ${{ env.RELEASE_BRANCH }} or master, got ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
9187
exit 1
9288
89+
# Set commit author information to the user that triggered the release workflow
9390
- name: "Set git author information"
9491
run: |
95-
git config user.name "${GIT_AUTHOR_NAME}"
96-
git config user.email "${GIT_AUTHOR_EMAIL}"
92+
GITHUB_USER_NAME=$(gh api users/${{ github.actor }} --jq '.name')
93+
GITHUB_USER_ID=$(gh api users/${{ github.actor }} --jq '.id')
94+
git config user.name "${GITHUB_USER_NAME}"
95+
git config user.email "${GITHUB_USER_ID}+${{ github.actor }}@users.noreply.github.com"
9796
9897
# If a non-patch release is created from a branch other than its
9998
# maintenance branch, create that branch from the current one and push it

bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.bson.codecs.DecoderContext
2323
import org.bson.codecs.EncoderContext
2424
import org.bson.codecs.configuration.CodecConfigurationException
2525
import org.bson.codecs.configuration.CodecRegistries.fromProviders
26+
import org.bson.codecs.kotlin.samples.Box
2627
import org.bson.codecs.kotlin.samples.DataClassEmbedded
2728
import org.bson.codecs.kotlin.samples.DataClassListOfDataClasses
2829
import org.bson.codecs.kotlin.samples.DataClassListOfListOfDataClasses
@@ -55,6 +56,7 @@ import org.bson.codecs.kotlin.samples.DataClassWithMutableMap
5556
import org.bson.codecs.kotlin.samples.DataClassWithMutableSet
5657
import org.bson.codecs.kotlin.samples.DataClassWithNestedParameterized
5758
import org.bson.codecs.kotlin.samples.DataClassWithNestedParameterizedDataClass
59+
import org.bson.codecs.kotlin.samples.DataClassWithNullableGeneric
5860
import org.bson.codecs.kotlin.samples.DataClassWithNulls
5961
import org.bson.codecs.kotlin.samples.DataClassWithObjectIdAndBsonDocument
6062
import org.bson.codecs.kotlin.samples.DataClassWithPair
@@ -131,6 +133,25 @@ class DataClassCodecTest {
131133
assertDecodesTo(withStoredNulls, dataClass)
132134
}
133135

136+
@Test
137+
fun testDataClassWithNullableGenericsNotNull() {
138+
val expected =
139+
"""{
140+
| "box": {"boxed": "String"}
141+
|}"""
142+
.trimMargin()
143+
144+
val dataClass = DataClassWithNullableGeneric(Box("String"))
145+
assertRoundTrips(expected, dataClass)
146+
}
147+
148+
@Test
149+
fun testDataClassWithNullableGenericsNull() {
150+
val expected = """{"box": {}}"""
151+
val dataClass = DataClassWithNullableGeneric(Box(null))
152+
assertRoundTrips(expected, dataClass)
153+
}
154+
134155
@Test
135156
fun testDataClassSelfReferential() {
136157
val expected =

bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,7 @@ data class DataClassWithFailingInit(val id: String) {
162162
data class DataClassWithSequence(val value: Sequence<String>)
163163

164164
data class DataClassWithJVMErasure(val duration: Duration, val ints: List<Int>)
165+
166+
data class Box<T>(val boxed: T)
167+
168+
data class DataClassWithNullableGeneric(val box: Box<String?>)

bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ internal class DefaultBsonEncoder(
139139
return true
140140
}
141141

142+
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
143+
deferredElementName?.let {
144+
if (value != null || configuration.explicitNulls) {
145+
encodeName(it)
146+
super.encodeSerializableValue(serializer, value)
147+
} else {
148+
deferredElementName = null
149+
}
150+
}
151+
?: super.encodeSerializableValue(serializer, value)
152+
}
153+
142154
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) {
143155
deferredElementName?.let {
144156
if (value != null || configuration.explicitNulls) {
@@ -158,7 +170,14 @@ internal class DefaultBsonEncoder(
158170
override fun encodeDouble(value: Double) = writer.writeDouble(value)
159171
override fun encodeInt(value: Int) = writer.writeInt32(value)
160172
override fun encodeLong(value: Long) = writer.writeInt64(value)
161-
override fun encodeNull() = writer.writeNull()
173+
override fun encodeNull() {
174+
deferredElementName?.let {
175+
if (configuration.explicitNulls) {
176+
encodeName(it)
177+
}
178+
}
179+
writer.writeNull()
180+
}
162181

163182
override fun encodeString(value: String) {
164183
when (state) {

bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.bson.BsonUndefined
3333
import org.bson.codecs.DecoderContext
3434
import org.bson.codecs.EncoderContext
3535
import org.bson.codecs.configuration.CodecConfigurationException
36+
import org.bson.codecs.kotlinx.samples.Box
3637
import org.bson.codecs.kotlinx.samples.DataClassBsonValues
3738
import org.bson.codecs.kotlinx.samples.DataClassContainsOpen
3839
import org.bson.codecs.kotlinx.samples.DataClassContainsValueClass
@@ -76,6 +77,7 @@ import org.bson.codecs.kotlinx.samples.DataClassWithMutableMap
7677
import org.bson.codecs.kotlinx.samples.DataClassWithMutableSet
7778
import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterized
7879
import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterizedDataClass
80+
import org.bson.codecs.kotlinx.samples.DataClassWithNullableGeneric
7981
import org.bson.codecs.kotlinx.samples.DataClassWithNulls
8082
import org.bson.codecs.kotlinx.samples.DataClassWithPair
8183
import org.bson.codecs.kotlinx.samples.DataClassWithParameterizedDataClass
@@ -202,6 +204,27 @@ class KotlinSerializerCodecTest {
202204
assertRoundTrips(expectedNulls, dataClass, altConfiguration)
203205
}
204206

207+
@Test
208+
fun testDataClassWithNullableGenericsNotNull() {
209+
val expected =
210+
"""{
211+
| "box": {"boxed": "String"}
212+
|}"""
213+
.trimMargin()
214+
215+
val dataClass = DataClassWithNullableGeneric(Box("String"))
216+
assertRoundTrips(expected, dataClass)
217+
}
218+
219+
@Test
220+
fun testDataClassWithNullableGenericsNull() {
221+
val expectedDefault = """{"box": {}}"""
222+
val dataClass = DataClassWithNullableGeneric(Box(null))
223+
assertRoundTrips(expectedDefault, dataClass)
224+
val expectedNull = """{"box": {"boxed": null}}"""
225+
assertRoundTrips(expectedNull, dataClass, altConfiguration)
226+
}
227+
205228
@Test
206229
fun testDataClassSelfReferential() {
207230
val expected =

bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,7 @@ data class DataClassWithFailingInit(val id: String) {
294294
}
295295

296296
@Serializable data class DataClassWithSequence(val value: Sequence<String>)
297+
298+
@Serializable data class Box<T>(val boxed: T)
299+
300+
@Serializable data class DataClassWithNullableGeneric(val box: Box<String?>)

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,19 +163,44 @@ private <V> PropertyModel<V> getSpecializedPropertyModel(final PropertyModel<V>
163163
static final class NeedSpecializationCodec<T> extends PojoCodec<T> {
164164
private final ClassModel<T> classModel;
165165
private final DiscriminatorLookup discriminatorLookup;
166+
private final CodecRegistry codecRegistry;
166167

167-
NeedSpecializationCodec(final ClassModel<T> classModel, final DiscriminatorLookup discriminatorLookup) {
168+
NeedSpecializationCodec(final ClassModel<T> classModel, final DiscriminatorLookup discriminatorLookup, final CodecRegistry codecRegistry) {
168169
this.classModel = classModel;
169170
this.discriminatorLookup = discriminatorLookup;
171+
this.codecRegistry = codecRegistry;
170172
}
171173

172174
@Override
173-
public T decode(final BsonReader reader, final DecoderContext decoderContext) {
174-
throw exception();
175+
public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) {
176+
if (value.getClass().equals(classModel.getType())) {
177+
throw exception();
178+
}
179+
tryEncode(codecRegistry.get(value.getClass()), writer, value, encoderContext);
175180
}
176181

177182
@Override
178-
public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) {
183+
public T decode(final BsonReader reader, final DecoderContext decoderContext) {
184+
return tryDecode(reader, decoderContext);
185+
}
186+
187+
@SuppressWarnings("unchecked")
188+
private <A> void tryEncode(final Codec<A> codec, final BsonWriter writer, final T value, final EncoderContext encoderContext) {
189+
try {
190+
codec.encode(writer, (A) value, encoderContext);
191+
} catch (Exception e) {
192+
throw exception();
193+
}
194+
}
195+
196+
@SuppressWarnings("unchecked")
197+
public T tryDecode(final BsonReader reader, final DecoderContext decoderContext) {
198+
Codec<T> codec = PojoCodecImpl.<T>getCodecFromDocument(reader, classModel.useDiscriminator(), classModel.getDiscriminatorKey(),
199+
codecRegistry, discriminatorLookup, null, classModel.getName());
200+
if (codec != null) {
201+
return codec.decode(reader, decoderContext);
202+
}
203+
179204
throw exception();
180205
}
181206

0 commit comments

Comments
 (0)