/**
* Copyright 2015 StreamSets Inc.
*
* Licensed under the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 com.streamsets.pipeline.lib.parser.json;
import com.streamsets.pipeline.api.Field;
import com.streamsets.pipeline.api.Record;
import com.streamsets.pipeline.api.Stage;
import com.streamsets.pipeline.api.ext.ContextExtensions;
import com.streamsets.pipeline.api.ext.JsonObjectReader;
import com.streamsets.pipeline.api.ext.io.ObjectLengthException;
import com.streamsets.pipeline.api.ext.io.OverrunReader;
import com.streamsets.pipeline.api.ext.json.Mode;
import com.streamsets.pipeline.lib.parser.AbstractDataParser;
import com.streamsets.pipeline.lib.parser.DataParserException;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class JsonCharDataParser extends AbstractDataParser {
private final Stage.Context context;
private final String readerId;
private final int maxObjectLen;
private final JsonObjectReader parser;
private boolean eof;
public JsonCharDataParser(Stage.Context context, String readerId, OverrunReader reader, long readerOffset,
Mode mode, int maxObjectLen) throws IOException {
this.context = context;
this.readerId = readerId;
this.maxObjectLen = maxObjectLen;
parser = ((ContextExtensions) context).createJsonObjectReader(
reader,
readerOffset,
maxObjectLen,
mode,
Object.class
);
}
@Override
public Record parse() throws IOException, DataParserException {
Record record = null;
long offset = parser.getReaderPosition();
try {
Object json = parser.read();
if (json != null) {
record = createRecord(offset, json);
} else {
eof = true;
}
} catch (ObjectLengthException ex) {
throw new DataParserException(Errors.JSON_PARSER_02, readerId, offset, maxObjectLen);
}
return record;
}
public Field parseAsField() throws IOException, DataParserException {
long offset = parser.getReaderPosition();
try {
Object json = parser.read();
return (json != null) ? jsonToField(json, offset) : null;
} catch (ObjectLengthException ex) {
throw new DataParserException(Errors.JSON_PARSER_02, readerId, offset, maxObjectLen);
}
}
protected Record createRecord(long offset, Object json) throws DataParserException {
Record record = context.createRecord(readerId + "::" + offset);
record.set(jsonToField(json, offset));
return record;
}
@SuppressWarnings("unchecked")
protected Field jsonToField(Object json, long offset) throws DataParserException {
Field field;
if (json == null) {
field = Field.create(Field.Type.STRING, null);
} else if (json instanceof List) {
List jsonList = (List) json;
List<Field> list = new ArrayList<>(jsonList.size());
for (Object element : jsonList) {
list.add(jsonToField(element, offset));
}
field = Field.create(list);
} else if (json instanceof Map) {
Map<String, Object> jsonMap = (Map<String, Object>) json;
Map<String, Field> map = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : jsonMap.entrySet()) {
map.put(entry.getKey(), jsonToField(entry.getValue(), offset));
}
field = Field.create(map);
} else if (json instanceof String) {
field = Field.create((String) json);
} else if (json instanceof Boolean) {
field = Field.create((Boolean) json);
} else if (json instanceof Character) {
field = Field.create((Character) json);
} else if (json instanceof Byte) {
field = Field.create((Byte) json);
} else if (json instanceof Short) {
field = Field.create((Short) json);
} else if (json instanceof Integer) {
field = Field.create((Integer) json);
} else if (json instanceof Long) {
field = Field.create((Long) json);
} else if (json instanceof Float) {
field = Field.create((Float) json);
} else if (json instanceof Double) {
field = Field.create((Double) json);
} else if (json instanceof byte[]) {
field = Field.create((byte[]) json);
} else if (json instanceof Date) {
field = Field.createDate((Date) json);
} else if (json instanceof BigDecimal) {
field = Field.create((BigDecimal) json);
} else if (json instanceof BigInteger) {
field = Field.create(new BigDecimal((BigInteger) json));
} else {
throw new DataParserException(Errors.JSON_PARSER_01, readerId, offset, json.getClass().getSimpleName());
}
return field;
}
@Override
public String getOffset() {
return eof ? String.valueOf(-1) : String.valueOf(parser.getReaderPosition());
}
@Override
public void close() throws IOException {
parser.close();
}
}