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 @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (source != null) { if (source != null) {
builder.rawValue(new BytesArray(source), XContentType.JSON); builder.rawValue(new BytesArray(source).streamInput(), XContentType.JSON);
} else { } else {
builder.startObject().endObject(); builder.startObject().endObject();
} }

View File

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

View File

@ -19,8 +19,6 @@
package org.elasticsearch.common.xcontent; package org.elasticsearch.common.xcontent;
import org.elasticsearch.common.bytes.BytesReference;
import java.io.Closeable; import java.io.Closeable;
import java.io.Flushable; import java.io.Flushable;
import java.io.IOException; import java.io.IOException;
@ -99,28 +97,9 @@ public interface XContentGenerator extends Closeable, Flushable {
void writeRawField(String name, InputStream value, XContentType xContentType) throws IOException; void writeRawField(String name, InputStream value, XContentType xContentType) throws IOException;
/** /**
* Writes a raw field with the given bytes as the value * Writes a raw value taken from the bytes in the stream
* @deprecated use {@link #writeRawField(String, BytesReference, XContentType)} to avoid content type auto-detection
*/ */
@Deprecated void writeRawValue(InputStream value, XContentType xContentType) throws IOException;
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 copyCurrentStructure(XContentParser parser) 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.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate; import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContent; import org.elasticsearch.common.xcontent.XContent;
@ -333,51 +331,33 @@ public class JsonXContentGenerator implements XContentGenerator {
} }
@Override @Override
public final void writeRawField(String name, BytesReference content) throws IOException { public void writeRawValue(InputStream stream, XContentType xContentType) throws IOException {
XContentType contentType = XContentFactory.xContentType(content); if (mayWriteRawData(xContentType) == false) {
if (contentType == null) { copyRawValue(stream, xContentType.xContent());
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());
} else { } else {
if (generator.getOutputContext().getCurrentName() != null) { if (generator.getOutputContext().getCurrentName() != null) {
// If we've just started a field we'll need to add the separator // If we've just started a field we'll need to add the separator
generator.writeRaw(':'); generator.writeRaw(':');
} }
flush(); flush();
content.writeTo(os); transfer(stream, os);
writeEndRaw(); 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) { private boolean mayWriteRawData(XContentType contentType) {
// When the current generator is filtered (ie filter != null) // When the current generator is filtered (ie filter != null)
// or the content is in a different format than the current generator, // or the content is in a different format than the current generator,
@ -394,13 +374,12 @@ public class JsonXContentGenerator implements XContentGenerator {
return true; 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 // EMPTY is safe here because we never call namedObject
try (StreamInput input = content.streamInput(); try (XContentParser parser = xContent
XContentParser parser = xContent
// It's okay to pass the throwing deprecation handler because we // It's okay to pass the throwing deprecation handler because we
// should not be writing raw fields when generating JSON // 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); copyCurrentStructure(parser);
} }
} }

View File

@ -23,8 +23,10 @@ import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
@ -81,7 +83,8 @@ public class RestGetSourceAction extends BaseRestHandler {
if (response.isSourceEmpty()) { if (response.isSourceEmpty()) {
return new BytesRestResponse(NOT_FOUND, builder); return new BytesRestResponse(NOT_FOUND, builder);
} else { } else {
builder.rawValue(response.getSourceInternal()); final BytesReference source = response.getSourceInternal();
builder.rawValue(source.streamInput(), XContentFactory.xContentType(source));
return new BytesRestResponse(OK, builder); 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.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -57,7 +58,7 @@ public class RawTaskStatus implements Task.Status {
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.rawValue(status); return builder.rawValue(status.streamInput(), XContentFactory.xContentType(status));
} }
@Override @Override

View File

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