AbstractProcessor.java
package org.vlaskin.moexiss.entity.base;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.vlaskin.moexiss.InternalApi;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/** @hidden */
@Slf4j
@InternalApi
public abstract class AbstractProcessor<T extends BasicEntity<E>, E extends Enum<?> & TypedField>
{
private static final String INT_32 = "int32";
private static final String INT_64 = "int64";
private static final String DOUBLE = "double";
private static final String DATE = "date";
private static final String TIME = "time";
private static final String DATETIME = "datetime";
private static final String STRING = "string";
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final Set<UnknownAttribute> REPORTED_UNKNOWN_ATTRIBUTES = ConcurrentHashMap.newKeySet();
public abstract T processJsonElement(JsonElement jsonElement, JsonArray columns, JsonObject metadata);
protected void process(BasicEntity<E> entity, JsonElement jsonElement, JsonArray columns, JsonObject metadata)
{
int i = 0;
for (JsonElement column : columns)
{
JsonElement value = jsonElement.getAsJsonArray().get(i);
if (value.isJsonNull())
{
i++;
continue;
}
String columnName = column.getAsString();
String dataType = metadata.getAsJsonObject(columnName).get("type").getAsString();
try
{
processValue(entity, value, columnName, dataType);
}
catch (UnknownAttributeException e)
{
if (shouldLogUnknownAttribute(e.getEntity(), e.getAttribute()))
log.warn("{} - unknown attribute: {}", e.getEntity(), e.getAttribute());
}
i++;
}
}
static boolean shouldLogUnknownAttribute(Class<?> entity, String attribute)
{
return REPORTED_UNKNOWN_ATTRIBUTES.add(new UnknownAttribute(entity, attribute));
}
protected abstract void processValue(BasicEntity<E> entity, JsonElement value, String name, String type) throws UnknownAttributeException;
protected void processValue(BasicEntity<E> entity, E field, JsonElement value, String type, Class<?> clazz)
{
if (Boolean.class.equals(clazz) && (INT_32.equals(type) || INT_64.equals(type)))
{
int encodedValue = value.getAsInt();
if (encodedValue != 0 && encodedValue != 1)
throw new IllegalArgumentException("Boolean field '" + field
+ "' contains unsupported value " + encodedValue);
entity.booleanFields.put(field, encodedValue == 1);
}
else if (Integer.class.equals(clazz) && (INT_32.equals(type) || INT_64.equals(type)))
entity.integerFields.put(field, Math.toIntExact(value.getAsLong()));
else if (Long.class.equals(clazz) && (INT_64.equals(type) || INT_32.equals(type)))
entity.longFields.put(field, value.getAsLong());
else if (Double.class.equals(clazz) && (DOUBLE.equals(type) || INT_64.equals(type) || INT_32.equals(type)))
entity.doubleFields.put(field, value.getAsDouble());
else if (LocalDate.class.equals(clazz) && (DATE.equals(type) || STRING.equals(type)))
{
if ("0000-00-00".equals(value.getAsString()))
return;
try
{
entity.localDateFields.put(field, LocalDate.parse(value.getAsString()));
}
catch (DateTimeParseException e)
{
// Некоторые колонки, возвращаемые MOEX ISS, с типом "date" могут быть на самом деле типа "datetime".
// Например, колонка "YIELDDATE" в "marketdata_yields".
entity.localDateFields.put(field,
LocalDateTime.parse(value.getAsString(), DATE_TIME_FORMATTER).toLocalDate());
}
}
else if (LocalTime.class.equals(clazz) && TIME.equals(type))
entity.localTimeFields.put(field, LocalTime.parse(value.getAsString()));
else if (LocalDateTime.class.equals(clazz) && DATETIME.equals(type))
entity.localDateTimeFields.put(field,
LocalDateTime.parse(value.getAsString(), DATE_TIME_FORMATTER));
else if (String.class.equals(clazz) && STRING.equals(type))
entity.stringFields.put(field, value.getAsString());
else
throw new IllegalArgumentException("Data type '" + type + "' of field '" + field
+ "' is incompatible with " + clazz.getSimpleName());
}
@Getter
protected static class UnknownAttributeException extends Exception
{
private final Class<?> entity;
private final String attribute;
public UnknownAttributeException(Class<?> entity, String attribute)
{
super(entity + " - unknown attribute: " + attribute);
this.entity = entity;
this.attribute = attribute;
}
}
private record UnknownAttribute(Class<?> entity, String attribute)
{
}
}