Skip to content

Commit b82f981

Browse files
committed
MLE-27078 One more fix for reading JSON as a binary
DocumentManagerImpl was needlessly using a class field (state = bad!) to track whether the user had modified the metadata categories to retrieve. So e.g. in the Spark connector, when we set "ALL" on the doc manager, the state variable was set to true - even though "ALL" is the default. That results in another way of triggering bug MLE-27191. The class field is now gone in favor of a simple private method to determine if the user has modified the metadata categories to something besides just "ALL" - and it's more accurate now. One of the new tests passes as a result - i.e. doing a bulk read after setting metadataCategories to ALL.
1 parent 5e00335 commit b82f981

File tree

3 files changed

+78
-58
lines changed

3 files changed

+78
-58
lines changed

marklogic-client-api/src/main/java/com/marklogic/client/impl/DocumentManagerImpl.java

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44
package com.marklogic.client.impl;
55

@@ -43,30 +43,23 @@
4343
abstract class DocumentManagerImpl<R extends AbstractReadHandle, W extends AbstractWriteHandle>
4444
extends AbstractLoggingManager implements DocumentManager<R, W>,
4545
TemporalDocumentManager<R, W> {
46+
4647
static final private long DEFAULT_PAGE_LENGTH = 50;
4748

4849
static final private Logger logger = LoggerFactory
4950
.getLogger(DocumentManagerImpl.class);
5051

51-
private boolean isProcessedMetadataModified = false;
52-
final private Set<Metadata> processedMetadata = new HashSet<Metadata>() {
53-
@Override
54-
public boolean add(Metadata e) {
55-
isProcessedMetadataModified = true;
56-
return super.add(e);
57-
}
52+
private boolean isMetadataCategoriesNotJustAll() {
53+
return metadataCategories.size() != 1 ||
54+
!Metadata.ALL.equals(metadataCategories.iterator().next());
55+
}
5856

59-
@Override
60-
public boolean addAll(Collection<? extends Metadata> c) {
61-
isProcessedMetadataModified = true;
62-
return super.addAll(c);
63-
}
64-
};
65-
{
66-
processedMetadata.add(Metadata.ALL);
67-
// we need to know if the user modifies after us
68-
isProcessedMetadataModified = false;
69-
}
57+
final private Set<Metadata> metadataCategories = new HashSet<>();
58+
59+
{
60+
// Initialize the default metadata to retrieve on a read.
61+
metadataCategories.add(Metadata.ALL);
62+
}
7063

7164
private RESTServices services;
7265
private Format contentFormat;
@@ -113,24 +106,25 @@ public void setContentFormat(Format format) {
113106
@Override
114107
public void setMetadataCategories(Set<Metadata> categories) {
115108
clearMetadataCategories();
116-
processedMetadata.addAll(categories);
109+
metadataCategories.addAll(categories);
117110
}
118111

119112
@Override
120113
public void setMetadataCategories(Metadata... categories) {
121114
clearMetadataCategories();
122-
for (Metadata category : categories)
123-
processedMetadata.add(category);
115+
for (Metadata category : categories) {
116+
metadataCategories.add(category);
117+
}
124118
}
125119

126120
@Override
127121
public Set<Metadata> getMetadataCategories() {
128-
return processedMetadata;
122+
return metadataCategories;
129123
}
130124

131125
@Override
132126
public void clearMetadataCategories() {
133-
processedMetadata.clear();
127+
metadataCategories.clear();
134128
}
135129

136130
@Override
@@ -374,7 +368,7 @@ public <T extends R> T read(DocumentDescriptor desc,
374368
requestLogger,
375369
desc,
376370
transaction,
377-
(metadataHandle != null) ? processedMetadata : null,
371+
(metadataHandle != null) ? metadataCategories : null,
378372
mergeTransformParameters((transform != null) ? transform
379373
: getReadTransform(), extraParams), metadataHandle, contentHandle);
380374

@@ -446,9 +440,8 @@ public DocumentPage read(long serverTimestamp, ServerTransform transform, Transa
446440
requestLogger,
447441
serverTimestamp,
448442
transaction,
449-
// the default for bulk is no metadata, which differs from the normal
450-
// default of ALL
451-
(isProcessedMetadataModified || !withContent) ? processedMetadata : null,
443+
// the default for bulk is no metadata, which differs from the normal default of ALL
444+
(isMetadataCategoriesNotJustAll() || !withContent) ? metadataCategories : null,
452445
nonDocumentFormat,
453446
mergeTransformParameters((transform != null) ? transform : getReadTransform(), extraParams),
454447
withContent,
@@ -542,10 +535,8 @@ private DocumentPage search(SearchQueryDefinition querydef, long start,
542535
}
543536
}
544537

545-
// the default for bulk is no metadata, which differs from the normal
546-
// default of ALL
547-
Set<Metadata> metadata = isProcessedMetadataModified ? processedMetadata
548-
: null;
538+
// the default for bulk is no metadata, which differs from the normal default of ALL
539+
Set<Metadata> metadata = isMetadataCategoriesNotJustAll() ? metadataCategories : null;
549540
return services.getBulkDocuments(requestLogger, serverTimestamp, querydef, start,
550541
getPageLength(), transaction, searchHandle, searchView, metadata,
551542
nonDocumentFormat, getReadTransform(), null, forestName);
@@ -943,7 +934,7 @@ protected TemporalDescriptor write(DocumentDescriptor desc, String temporalDocum
943934
requestLogger,
944935
desc,
945936
transaction,
946-
(metadataHandle != null) ? processedMetadata : null,
937+
(metadataHandle != null) ? metadataCategories : null,
947938
mergeTransformParameters((transform != null) ? transform
948939
: getWriteTransform(), extraParams), metadataHandle, contentHandle);
949940
}
@@ -1266,7 +1257,7 @@ protected DocumentDescriptorImpl create(DocumentUriTemplate template,
12661257
requestLogger,
12671258
template,
12681259
transaction,
1269-
(metadataHandle != null) ? processedMetadata : null,
1260+
(metadataHandle != null) ? metadataCategories : null,
12701261
mergeTransformParameters((transform != null) ? transform
12711262
: getWriteTransform(), extraParams), metadataHandle, contentHandle);
12721263
}
@@ -1326,7 +1317,7 @@ public void patch(DocumentDescriptor desc, DocumentPatchHandle patch,
13261317
DocumentPatchHandleImpl builtPatch = (patch instanceof DocumentPatchHandleImpl) ? (DocumentPatchHandleImpl) patch
13271318
: null;
13281319
services.patchDocument(requestLogger, desc, transaction,
1329-
(builtPatch != null) ? builtPatch.getMetadata() : processedMetadata,
1320+
(builtPatch != null) ? builtPatch.getMetadata() : metadataCategories,
13301321
(builtPatch != null) ? builtPatch.isOnContent() : true, patch);
13311322
}
13321323

@@ -1360,7 +1351,7 @@ public void patch(String uri, String temporalDocumentURI, String temporalCollec
13601351
extraParams = addTemporalParams(extraParams, temporalCollection, temporalDocumentURI, null);
13611352
DocumentPatchHandleImpl builtPatch = (patch instanceof DocumentPatchHandleImpl) ? (DocumentPatchHandleImpl) patch
13621353
: null;
1363-
services.patchDocument(requestLogger, new DocumentDescriptorImpl(uri, true), transaction, (builtPatch != null) ? builtPatch.getMetadata() : processedMetadata,
1354+
services.patchDocument(requestLogger, new DocumentDescriptorImpl(uri, true), transaction, (builtPatch != null) ? builtPatch.getMetadata() : metadataCategories,
13641355
(builtPatch != null) ? builtPatch.isOnContent() : true, extraParams, sourceDocumentURI, patch);
13651356
}
13661357

@@ -1416,7 +1407,7 @@ public void writeDefaultMetadata(String uri, Transaction transaction)
14161407
logger.info("Resetting metadata for {}", uri);
14171408

14181409
services.deleteDocument(requestLogger,
1419-
new DocumentDescriptorImpl(uri, true), transaction, processedMetadata,
1410+
new DocumentDescriptorImpl(uri, true), transaction, metadataCategories,
14201411
getWriteParams());
14211412
}
14221413

@@ -1433,7 +1424,7 @@ public void writeDefaultMetadata(Transaction transaction, String... uris)
14331424
if (uris.length == 0)
14341425
throw new IllegalArgumentException(
14351426
"Resetting document metadata with empty identifier list");
1436-
services.delete(requestLogger, transaction, processedMetadata, uris);
1427+
services.delete(requestLogger, transaction, metadataCategories, uris);
14371428
}
14381429

14391430
@Override

marklogic-client-api/src/test/java/com/marklogic/client/test/document/ReadJsonAsBinaryTest.java

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,39 @@
1717

1818
import static org.junit.jupiter.api.Assertions.assertEquals;
1919

20+
@Disabled("See MLE-27191 for description of the server bug")
2021
class ReadJsonAsBinaryTest extends AbstractClientTest {
2122

23+
private static final String URI = "/a.json";
24+
2225
@Test
23-
@Disabled("See MLE-27191 for description of the server bug")
24-
void test() {
26+
void genericDocumentManager() {
2527
try (DatabaseClient client = Common.newClient()) {
26-
final String uri = "/a.json";
27-
writeJsonAsBinary(uri, client);
28+
writeJsonAsBinary(URI, client);
2829

2930
GenericDocumentManager docManager = client.newDocumentManager();
31+
// A bulk read works...
32+
verifyBulkRead(docManager);
33+
// But a request for a single URI does not!
34+
verifySingleRead(docManager);
35+
}
36+
}
3037

31-
// A multipart request returns the correct document format.
32-
try (DocumentPage page = docManager.read(uri)) {
33-
DocumentRecord record = page.next();
34-
assertEquals(uri, record.getUri());
35-
assertEquals("application/json", record.getMimetype());
36-
assertEquals(Format.BINARY, record.getFormat());
37-
}
38+
@Test
39+
void managerWithModifiedMetadataCategories() {
40+
try (DatabaseClient client = Common.newClient()) {
41+
writeJsonAsBinary(URI, client);
3842

39-
// But a request for a single URI does not!
40-
try (InputStreamHandle handle = docManager.read(uri, new InputStreamHandle())) {
41-
assertEquals("application/json", handle.getMimetype());
42-
assertEquals(Format.BINARY, handle.getFormat(), "Unfortunately due to MLE-27191, the " +
43-
"format is JSON instead of binary. So this assertion will fail until that bug is fixed. " +
44-
"For a Java Client user, the workaround is to use the read method above and get a DocumentPage " +
45-
"back, as a multipart response seems to identify the correct headers.");
46-
}
43+
GenericDocumentManager docManager = client.newDocumentManager();
4744

45+
// Setting metadata categories to ALL should have no effect since that results in no metadata being
46+
// retrieved on a bulk read.
47+
docManager.setMetadataCategories(DocumentManager.Metadata.ALL);
48+
verifyBulkRead(docManager);
49+
50+
// Setting metadata categories to anything besides ALL will cause the bug
51+
docManager.setMetadataCategories(DocumentManager.Metadata.PERMISSIONS);
52+
verifyBulkRead(docManager);
4853
}
4954
}
5055

@@ -56,4 +61,23 @@ private void writeJsonAsBinary(String uri, DatabaseClient client) {
5661
jsonDocManager.setWriteTransform(new ServerTransform("toBinary"));
5762
jsonDocManager.write(uri, metadata, new JacksonHandle(new ObjectMapper().createObjectNode().put("a", 1)));
5863
}
64+
65+
private void verifySingleRead(GenericDocumentManager docManager) {
66+
try (InputStreamHandle handle = docManager.read(URI, new InputStreamHandle())) {
67+
assertEquals("application/json", handle.getMimetype());
68+
assertEquals(Format.BINARY, handle.getFormat(), "Unfortunately due to MLE-27191, the " +
69+
"format is JSON instead of binary. So this assertion will fail until that bug is fixed. " +
70+
"For a Java Client user, the workaround is to use the read method above and get a DocumentPage " +
71+
"back, as a multipart response seems to identify the correct headers.");
72+
}
73+
}
74+
75+
private void verifyBulkRead(GenericDocumentManager docManager) {
76+
try (DocumentPage page = docManager.read(URI)) {
77+
DocumentRecord record = page.next();
78+
assertEquals(URI, record.getUri());
79+
assertEquals("application/json", record.getMimetype());
80+
assertEquals(Format.BINARY, record.getFormat());
81+
}
82+
}
5983
}

test-app/build.gradle

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44

55
buildscript {
@@ -25,6 +25,11 @@ plugins {
2525

2626
apply plugin: "com.marklogic.ml-gradle"
2727

28+
// Sometimes, 3 x 20 isn't enough on Jenkins.
29+
mlWaitTillReady {
30+
maxAttempts = 40
31+
}
32+
2833
dependencies {
2934
implementation "io.undertow:undertow-core:2.3.20.Final"
3035
implementation "io.undertow:undertow-servlet:2.3.20.Final"

0 commit comments

Comments
 (0)