| // Copyright (C) 2018 The Android Open Source Project, 2009-2015 Elasticsearch | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.gerrit.elasticsearch.builders; | |
| import static java.nio.charset.StandardCharsets.UTF_8; | |
| import static java.time.format.DateTimeFormatter.ISO_INSTANT; | |
| import com.fasterxml.jackson.core.JsonEncoding; | |
| import com.fasterxml.jackson.core.JsonFactory; | |
| import com.fasterxml.jackson.core.JsonGenerator; | |
| import com.fasterxml.jackson.core.json.JsonReadFeature; | |
| import com.fasterxml.jackson.core.json.JsonWriteFeature; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.Closeable; | |
| import java.io.IOException; | |
| import java.util.Date; | |
| /** A trimmed down and modified version of org.elasticsearch.common.xcontent.XContentBuilder. */ | |
| public final class XContentBuilder implements Closeable { | |
| private final JsonGenerator generator; | |
| private final ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
| /** | |
| * Constructs a new builder. Make sure to call {@link #close()} when the builder is done with. | |
| * Inspired from org.elasticsearch.common.xcontent.json.JsonXContent static block. | |
| */ | |
| public XContentBuilder() throws IOException { | |
| this.generator = | |
| JsonFactory.builder() | |
| .configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES, true) | |
| .configure(JsonWriteFeature.QUOTE_FIELD_NAMES, true) | |
| .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true) | |
| .configure(JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW, false) | |
| .build() | |
| .createGenerator(bos, JsonEncoding.UTF8); | |
| } | |
| public XContentBuilder startObject(String name) throws IOException { | |
| field(name); | |
| startObject(); | |
| return this; | |
| } | |
| public XContentBuilder startObject() throws IOException { | |
| generator.writeStartObject(); | |
| return this; | |
| } | |
| public XContentBuilder endObject() throws IOException { | |
| generator.writeEndObject(); | |
| return this; | |
| } | |
| public void startArray(String name) throws IOException { | |
| field(name); | |
| startArray(); | |
| } | |
| private void startArray() throws IOException { | |
| generator.writeStartArray(); | |
| } | |
| public void endArray() throws IOException { | |
| generator.writeEndArray(); | |
| } | |
| public XContentBuilder field(String name) throws IOException { | |
| generator.writeFieldName(name); | |
| return this; | |
| } | |
| public XContentBuilder field(String name, String value) throws IOException { | |
| field(name); | |
| generator.writeString(value); | |
| return this; | |
| } | |
| public XContentBuilder field(String name, int value) throws IOException { | |
| field(name); | |
| generator.writeNumber(value); | |
| return this; | |
| } | |
| public XContentBuilder field(String name, Iterable<?> value) throws IOException { | |
| startArray(name); | |
| for (Object o : value) { | |
| value(o); | |
| } | |
| endArray(); | |
| return this; | |
| } | |
| public XContentBuilder field(String name, Object value) throws IOException { | |
| field(name); | |
| writeValue(value); | |
| return this; | |
| } | |
| public XContentBuilder value(Object value) throws IOException { | |
| writeValue(value); | |
| return this; | |
| } | |
| public XContentBuilder field(String name, boolean value) throws IOException { | |
| field(name); | |
| generator.writeBoolean(value); | |
| return this; | |
| } | |
| public XContentBuilder value(String value) throws IOException { | |
| generator.writeString(value); | |
| return this; | |
| } | |
| @Override | |
| public void close() { | |
| try { | |
| generator.close(); | |
| } catch (IOException e) { | |
| // ignore | |
| } | |
| } | |
| /** Returns a string representation of the builder (only applicable for text based xcontent). */ | |
| public String string() { | |
| close(); | |
| byte[] bytesArray = bos.toByteArray(); | |
| return new String(bytesArray, UTF_8); | |
| } | |
| private void writeValue(Object value) throws IOException { | |
| if (value == null) { | |
| generator.writeNull(); | |
| return; | |
| } | |
| Class<?> type = value.getClass(); | |
| if (type == String.class) { | |
| generator.writeString((String) value); | |
| } else if (type == Integer.class) { | |
| generator.writeNumber(((Integer) value)); | |
| } else if (type == byte[].class) { | |
| generator.writeBinary((byte[]) value); | |
| } else if (value instanceof Date) { | |
| generator.writeString(ISO_INSTANT.format(((Date) value).toInstant())); | |
| } else { | |
| // if this is a "value" object, like enum, DistanceUnit, ..., just toString it | |
| // yea, it can be misleading when toString a Java class, but really, jackson should be used in | |
| // that case | |
| generator.writeString(value.toString()); | |
| // throw new ElasticsearchIllegalArgumentException("type not supported for generic value | |
| // conversion: " + type); | |
| } | |
| } | |
| } |