All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.common.xcontent.support.XContentMapConverter Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * Licensed to ElasticSearch and Shay Banon under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. ElasticSearch licenses this
 * file to you 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 org.elasticsearch.common.xcontent.support;

import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentGenerator;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.*;

/**
 *
 */
public class XContentMapConverter {

    public static interface MapFactory {
        Map newMap();
    }

    public static final MapFactory SIMPLE_MAP_FACTORY = new MapFactory() {
        @Override
        public Map newMap() {
            return new HashMap();
        }
    };

    public static final MapFactory ORDERED_MAP_FACTORY = new MapFactory() {
        @Override
        public Map newMap() {
            return new LinkedHashMap();
        }
    };

    public static Map readMap(XContentParser parser) throws IOException {
        return readMap(parser, SIMPLE_MAP_FACTORY);
    }

    public static Map readOrderedMap(XContentParser parser) throws IOException {
        return readMap(parser, ORDERED_MAP_FACTORY);
    }

    public static Map readMap(XContentParser parser, MapFactory mapFactory) throws IOException {
        Map map = mapFactory.newMap();
        XContentParser.Token t = parser.currentToken();
        if (t == null) {
            t = parser.nextToken();
        }
        if (t == XContentParser.Token.START_OBJECT) {
            t = parser.nextToken();
        }
        for (; t == XContentParser.Token.FIELD_NAME; t = parser.nextToken()) {
            // Must point to field name
            String fieldName = parser.currentName();
            // And then the value...
            t = parser.nextToken();
            Object value = readValue(parser, mapFactory, t);
            map.put(fieldName, value);
        }
        return map;
    }

    private static List readList(XContentParser parser, MapFactory mapFactory, XContentParser.Token t) throws IOException {
        ArrayList list = new ArrayList();
        while ((t = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            list.add(readValue(parser, mapFactory, t));
        }
        return list;
    }

    private static Object readValue(XContentParser parser, MapFactory mapFactory, XContentParser.Token t) throws IOException {
        if (t == XContentParser.Token.VALUE_NULL) {
            return null;
        } else if (t == XContentParser.Token.VALUE_STRING) {
            return parser.text();
        } else if (t == XContentParser.Token.VALUE_NUMBER) {
            XContentParser.NumberType numberType = parser.numberType();
            if (numberType == XContentParser.NumberType.INT) {
                return parser.intValue();
            } else if (numberType == XContentParser.NumberType.LONG) {
                return parser.longValue();
            } else if (numberType == XContentParser.NumberType.FLOAT) {
                return parser.floatValue();
            } else if (numberType == XContentParser.NumberType.DOUBLE) {
                return parser.doubleValue();
            }
        } else if (t == XContentParser.Token.VALUE_BOOLEAN) {
            return parser.booleanValue();
        } else if (t == XContentParser.Token.START_OBJECT) {
            return readMap(parser, mapFactory);
        } else if (t == XContentParser.Token.START_ARRAY) {
            return readList(parser, mapFactory, t);
        } else if (t == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
            return parser.binaryValue();
        }
        return null;
    }

    public static void writeMap(XContentGenerator gen, Map map) throws IOException {
        gen.writeStartObject();

        for (Map.Entry entry : map.entrySet()) {
            gen.writeFieldName(entry.getKey());
            Object value = entry.getValue();
            if (value == null) {
                gen.writeNull();
            } else {
                writeValue(gen, value);
            }
        }

        gen.writeEndObject();
    }

    private static void writeIterable(XContentGenerator gen, Iterable iterable) throws IOException {
        gen.writeStartArray();
        for (Object value : iterable) {
            writeValue(gen, value);
        }
        gen.writeEndArray();
    }

    private static void writeObjectArray(XContentGenerator gen, Object[] array) throws IOException {
        gen.writeStartArray();
        for (Object value : array) {
            writeValue(gen, value);
        }
        gen.writeEndArray();
    }

    private static void writeValue(XContentGenerator gen, Object value) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        Class type = value.getClass();
        if (type == String.class) {
            gen.writeString((String) value);
        } else if (type == Integer.class) {
            gen.writeNumber(((Integer) value).intValue());
        } else if (type == Long.class) {
            gen.writeNumber(((Long) value).longValue());
        } else if (type == Float.class) {
            gen.writeNumber(((Float) value).floatValue());
        } else if (type == Double.class) {
            gen.writeNumber(((Double) value).doubleValue());
        } else if (type == Short.class) {
            gen.writeNumber(((Short) value).shortValue());
        } else if (type == Boolean.class) {
            gen.writeBoolean(((Boolean) value).booleanValue());
        } else if (value instanceof Map) {
            writeMap(gen, (Map) value);
        } else if (value instanceof Iterable) {
            writeIterable(gen, (Iterable) value);
        } else if (value instanceof Object[]) {
            writeObjectArray(gen, (Object[]) value);
        } else if (type == byte[].class) {
            gen.writeBinary((byte[]) value);
        } else if (value instanceof Date) {
            gen.writeString(XContentBuilder.defaultDatePrinter.print(((Date) value).getTime()));
        } else if (value instanceof Calendar) {
            gen.writeString(XContentBuilder.defaultDatePrinter.print((((Calendar) value)).getTimeInMillis()));
        } else if (value instanceof BytesReference) {
            BytesReference bytes = (BytesReference) value;
            if (!bytes.hasArray()) {
                bytes = bytes.toBytesArray();
            }
            gen.writeBinary(bytes.array(), bytes.arrayOffset(), bytes.length());
        } else if (value instanceof Text) {
            Text text = (Text) value;
            if (text.hasBytes() && text.bytes().hasArray()) {
                gen.writeUTF8String(text.bytes().array(), text.bytes().arrayOffset(), text.bytes().length());
            } else if (text.hasString()) {
                gen.writeString(text.string());
            } else {
                BytesArray bytesArray = text.bytes().toBytesArray();
                gen.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length());
            }
        } else {
            gen.writeString(value.toString());
        }
    }
}