Decouple XContentGenerator and JsonXContentGenerator from BytesReference (#28772)

This removes the link these two classes have with BytesReference, in favor of an
`InputStream` approach.

Relates to #28504
This commit is contained in:
Lee Hinman 2018-02-22 14:22:37 -07:00 committed by GitHub
parent b29ba25c86
commit 5bb79558e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 87 deletions

View File

@ -323,7 +323,7 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (source != null) {
builder.rawValue(new BytesArray(source), XContentType.JSON);
builder.rawValue(new BytesArray(source).streamInput(), XContentType.JSON);
} else {
builder.startObject().endObject();
}

View File

@ -987,7 +987,7 @@ public final class XContentBuilder implements Releasable, Flushable {
*/
@Deprecated
public XContentBuilder rawField(String name, BytesReference value) throws IOException {
generator.writeRawField(name, value);
generator.writeRawField(name, value.streamInput());
return this;
}
@ -995,25 +995,15 @@ public final class XContentBuilder implements Releasable, Flushable {
* Writes a raw field with the given bytes as the value
*/
public XContentBuilder rawField(String name, BytesReference value, XContentType contentType) throws IOException {
generator.writeRawField(name, value, contentType);
generator.writeRawField(name, value.streamInput(), contentType);
return this;
}
/**
* Writes a value with the source coming directly from the bytes
* @deprecated use {@link #rawValue(BytesReference, XContentType)} to avoid content type auto-detection
* Writes a value with the source coming directly from the bytes in the stream
*/
@Deprecated
public XContentBuilder rawValue(BytesReference value) throws IOException {
generator.writeRawValue(value);
return this;
}
/**
* Writes a value with the source coming directly from the bytes
*/
public XContentBuilder rawValue(BytesReference value, XContentType contentType) throws IOException {
generator.writeRawValue(value, contentType);
public XContentBuilder rawValue(InputStream stream, XContentType contentType) throws IOException {
generator.writeRawValue(stream, contentType);
return this;
}

View File

@ -19,8 +19,6 @@
package org.elasticsearch.common.xcontent;
import org.elasticsearch.common.bytes.BytesReference;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
@ -99,28 +97,9 @@ public interface XContentGenerator extends Closeable, Flushable {
void writeRawField(String name, InputStream value, XContentType xContentType) throws IOException;
/**
* Writes a raw field with the given bytes as the value
* @deprecated use {@link #writeRawField(String, BytesReference, XContentType)} to avoid content type auto-detection
* Writes a raw value taken from the bytes in the stream
*/
@Deprecated
void writeRawField(String name, BytesReference value) throws IOException;
/**
* Writes a raw field with the given bytes as the value
*/
void writeRawField(String name, BytesReference value, XContentType xContentType) throws IOException;
/**
* Writes a value with the source coming directly from the bytes
* @deprecated use {@link #writeRawValue(BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
void writeRawValue(BytesReference value) throws IOException;
/**
* Writes a value with the source coming directly from the bytes
*/
void writeRawValue(BytesReference value, XContentType xContentType) throws IOException;
void writeRawValue(InputStream value, XContentType xContentType) throws IOException;
void copyCurrentStructure(XContentParser parser) throws IOException;

View File

@ -28,9 +28,7 @@ import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContent;
@ -333,51 +331,33 @@ public class JsonXContentGenerator implements XContentGenerator {
}
@Override
public final void writeRawField(String name, BytesReference content) throws IOException {
XContentType contentType = XContentFactory.xContentType(content);
if (contentType == null) {
throw new IllegalArgumentException("Can't write raw bytes whose xcontent-type can't be guessed");
}
writeRawField(name, content, contentType);
}
@Override
public final void writeRawField(String name, BytesReference content, XContentType contentType) throws IOException {
if (mayWriteRawData(contentType) == false) {
writeFieldName(name);
copyRawValue(content, contentType.xContent());
} else {
writeStartRaw(name);
flush();
content.writeTo(os);
writeEndRaw();
}
}
@Override
public final void writeRawValue(BytesReference content) throws IOException {
XContentType contentType = XContentFactory.xContentType(content);
if (contentType == null) {
throw new IllegalArgumentException("Can't write raw bytes whose xcontent-type can't be guessed");
}
writeRawValue(content, contentType);
}
@Override
public final void writeRawValue(BytesReference content, XContentType contentType) throws IOException {
if (mayWriteRawData(contentType) == false) {
copyRawValue(content, contentType.xContent());
public void writeRawValue(InputStream stream, XContentType xContentType) throws IOException {
if (mayWriteRawData(xContentType) == false) {
copyRawValue(stream, xContentType.xContent());
} else {
if (generator.getOutputContext().getCurrentName() != null) {
// If we've just started a field we'll need to add the separator
generator.writeRaw(':');
}
flush();
content.writeTo(os);
transfer(stream, os);
writeEndRaw();
}
}
// A basic copy of Java 9's InputStream#transferTo
private static long transfer(InputStream in, OutputStream out) throws IOException {
Objects.requireNonNull(out, "out");
long transferred = 0;
byte[] buffer = new byte[8192];
int read;
while ((read = in.read(buffer, 0, 8192)) >= 0) {
out.write(buffer, 0, read);
transferred += read;
}
return transferred;
}
private boolean mayWriteRawData(XContentType contentType) {
// When the current generator is filtered (ie filter != null)
// or the content is in a different format than the current generator,
@ -394,13 +374,12 @@ public class JsonXContentGenerator implements XContentGenerator {
return true;
}
protected void copyRawValue(BytesReference content, XContent xContent) throws IOException {
protected void copyRawValue(InputStream stream, XContent xContent) throws IOException {
// EMPTY is safe here because we never call namedObject
try (StreamInput input = content.streamInput();
XContentParser parser = xContent
try (XContentParser parser = xContent
// It's okay to pass the throwing deprecation handler because we
// should not be writing raw fields when generating JSON
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, input)) {
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) {
copyCurrentStructure(parser);
}
}

View File

@ -23,8 +23,10 @@ import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
@ -81,7 +83,8 @@ public class RestGetSourceAction extends BaseRestHandler {
if (response.isSourceEmpty()) {
return new BytesRestResponse(NOT_FOUND, builder);
} else {
builder.rawValue(response.getSourceInternal());
final BytesReference source = response.getSourceInternal();
builder.rawValue(source.streamInput(), XContentFactory.xContentType(source));
return new BytesRestResponse(OK, builder);
}
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import java.io.IOException;
import java.util.Map;
@ -57,7 +58,7 @@ public class RawTaskStatus implements Task.Status {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.rawValue(status);
return builder.rawValue(status.streamInput(), XContentFactory.xContentType(status));
}
@Override

View File

@ -748,7 +748,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
if (useStream) {
generator.writeRawField("bar", new ByteArrayInputStream(rawData));
} else {
generator.writeRawField("bar", new BytesArray(rawData));
generator.writeRawField("bar", new BytesArray(rawData).streamInput());
}
generator.writeEndObject();
}
@ -785,7 +785,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
os = new ByteArrayOutputStream();
try (XContentGenerator generator = xcontentType().xContent().createGenerator(os)) {
generator.writeRawValue(new BytesArray(rawData));
generator.writeRawValue(new BytesArray(rawData).streamInput(), source.type());
}
XContentParser parser = xcontentType().xContent()
@ -801,7 +801,7 @@ public abstract class BaseXContentTestCase extends ESTestCase {
try (XContentGenerator generator = xcontentType().xContent().createGenerator(os)) {
generator.writeStartObject();
generator.writeFieldName("test");
generator.writeRawValue(new BytesArray(rawData));
generator.writeRawValue(new BytesArray(rawData).streamInput(), source.type());
generator.writeEndObject();
}