org.opensearch.common.xcontent.JsonToStringXContentParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opensearch Show documentation
Show all versions of opensearch Show documentation
OpenSearch subproject :server
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
package org.opensearch.common.xcontent;
import org.opensearch.common.xcontent.json.JsonXContent;
import org.opensearch.core.common.bytes.BytesReference;
import org.opensearch.core.xcontent.AbstractXContentParser;
import org.opensearch.core.xcontent.DeprecationHandler;
import org.opensearch.core.xcontent.MediaType;
import org.opensearch.core.xcontent.MediaTypeRegistry;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentLocation;
import org.opensearch.core.xcontent.XContentParser;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.CharBuffer;
import java.util.ArrayList;
/**
* JsonToStringParser is the main parser class to transform JSON into stringFields in a XContentParser
* returns XContentParser with one parent field and subfields
* fieldName, fieldName._value, fieldName._valueAndPath
* @opensearch.internal
*/
public class JsonToStringXContentParser extends AbstractXContentParser {
private final String fieldTypeName;
private XContentParser parser;
private ArrayList valueList = new ArrayList<>();
private ArrayList valueAndPathList = new ArrayList<>();
private ArrayList keyList = new ArrayList<>();
private XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent);
private NamedXContentRegistry xContentRegistry;
private DeprecationHandler deprecationHandler;
private static final String VALUE_AND_PATH_SUFFIX = "._valueAndPath";
private static final String VALUE_SUFFIX = "._value";
private static final String DOT_SYMBOL = ".";
private static final String EQUAL_SYMBOL = "=";
public JsonToStringXContentParser(
NamedXContentRegistry xContentRegistry,
DeprecationHandler deprecationHandler,
XContentParser parser,
String fieldTypeName
) throws IOException {
super(xContentRegistry, deprecationHandler);
this.deprecationHandler = deprecationHandler;
this.xContentRegistry = xContentRegistry;
this.parser = parser;
this.fieldTypeName = fieldTypeName;
}
public XContentParser parseObject() throws IOException {
builder.startObject();
StringBuilder path = new StringBuilder(fieldTypeName);
parseToken(path, null);
builder.field(this.fieldTypeName, keyList);
builder.field(this.fieldTypeName + VALUE_SUFFIX, valueList);
builder.field(this.fieldTypeName + VALUE_AND_PATH_SUFFIX, valueAndPathList);
builder.endObject();
String jString = XContentHelper.convertToJson(BytesReference.bytes(builder), false, MediaTypeRegistry.JSON);
return JsonXContent.jsonXContent.createParser(this.xContentRegistry, this.deprecationHandler, String.valueOf(jString));
}
private void parseToken(StringBuilder path, String currentFieldName) throws IOException {
while (this.parser.nextToken() != Token.END_OBJECT) {
if (this.parser.currentName() != null) {
currentFieldName = this.parser.currentName();
}
StringBuilder parsedFields = new StringBuilder();
if (this.parser.currentToken() == Token.FIELD_NAME) {
path.append(DOT_SYMBOL).append(currentFieldName);
int dotIndex = currentFieldName.indexOf(DOT_SYMBOL);
String fieldNameSuffix = currentFieldName;
// The field name may be of the form foo.bar.baz
// If that's the case, each "part" is a key.
while (dotIndex >= 0) {
String fieldNamePrefix = fieldNameSuffix.substring(0, dotIndex);
if (!fieldNamePrefix.isEmpty()) {
this.keyList.add(fieldNamePrefix);
}
fieldNameSuffix = fieldNameSuffix.substring(dotIndex + 1);
dotIndex = fieldNameSuffix.indexOf(DOT_SYMBOL);
}
if (!fieldNameSuffix.isEmpty()) {
this.keyList.add(fieldNameSuffix);
}
} else if (this.parser.currentToken() == Token.START_ARRAY) {
parseToken(path, currentFieldName);
break;
} else if (this.parser.currentToken() == Token.END_ARRAY) {
// skip
} else if (this.parser.currentToken() == Token.START_OBJECT) {
parseToken(path, currentFieldName);
int dotIndex = path.lastIndexOf(DOT_SYMBOL, path.length());
if (dotIndex != -1 && path.length() > currentFieldName.length()) {
path.setLength(path.length() - currentFieldName.length() - 1);
}
} else {
if (!path.toString().contains(currentFieldName)) {
path.append(DOT_SYMBOL).append(currentFieldName);
}
parseValue(parsedFields);
this.valueList.add(parsedFields.toString());
this.valueAndPathList.add(path + EQUAL_SYMBOL + parsedFields);
int dotIndex = path.lastIndexOf(DOT_SYMBOL, path.length());
if (dotIndex != -1 && path.length() > currentFieldName.length()) {
path.setLength(path.length() - currentFieldName.length() - 1);
}
}
}
}
private void parseValue(StringBuilder parsedFields) throws IOException {
switch (this.parser.currentToken()) {
case VALUE_BOOLEAN:
case VALUE_NUMBER:
case VALUE_STRING:
case VALUE_NULL:
parsedFields.append(this.parser.textOrNull());
break;
// Handle other token types as needed
case FIELD_NAME:
case VALUE_EMBEDDED_OBJECT:
case END_ARRAY:
case START_ARRAY:
break;
default:
throw new IOException("Unsupported token type [" + parser.currentToken() + "]");
}
}
@Override
public MediaType contentType() {
return MediaTypeRegistry.JSON;
}
@Override
public Token nextToken() throws IOException {
return this.parser.nextToken();
}
@Override
public void skipChildren() throws IOException {
this.parser.skipChildren();
}
@Override
public Token currentToken() {
return this.parser.currentToken();
}
@Override
public String currentName() throws IOException {
return this.parser.currentName();
}
@Override
public String text() throws IOException {
return this.parser.text();
}
@Override
public CharBuffer charBuffer() throws IOException {
return this.parser.charBuffer();
}
@Override
public Object objectText() throws IOException {
return this.parser.objectText();
}
@Override
public Object objectBytes() throws IOException {
return this.parser.objectBytes();
}
@Override
public boolean hasTextCharacters() {
return this.parser.hasTextCharacters();
}
@Override
public char[] textCharacters() throws IOException {
return this.parser.textCharacters();
}
@Override
public int textLength() throws IOException {
return this.parser.textLength();
}
@Override
public int textOffset() throws IOException {
return this.parser.textOffset();
}
@Override
public Number numberValue() throws IOException {
return this.parser.numberValue();
}
@Override
public NumberType numberType() throws IOException {
return this.parser.numberType();
}
@Override
public byte[] binaryValue() throws IOException {
return this.parser.binaryValue();
}
@Override
public XContentLocation getTokenLocation() {
return this.parser.getTokenLocation();
}
@Override
protected boolean doBooleanValue() throws IOException {
return this.parser.booleanValue();
}
@Override
protected short doShortValue() throws IOException {
return this.parser.shortValue();
}
@Override
protected int doIntValue() throws IOException {
return this.parser.intValue();
}
@Override
protected long doLongValue() throws IOException {
return this.parser.longValue();
}
@Override
protected float doFloatValue() throws IOException {
return this.parser.floatValue();
}
@Override
protected double doDoubleValue() throws IOException {
return this.parser.doubleValue();
}
@Override
protected BigInteger doBigIntegerValue() throws IOException {
return this.parser.bigIntegerValue();
}
@Override
public boolean isClosed() {
return this.parser.isClosed();
}
@Override
public void close() throws IOException {
this.parser.close();
}
}