package io.swagger.inflector.converters;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.swagger.inflector.utils.ReflectionUtils;
import io.swagger.inflector.validators.ValidationError;
import io.swagger.inflector.validators.ValidationMessage;
import io.swagger.models.Model;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.parameters.QueryParameter;
import io.swagger.models.parameters.SerializableParameter;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.Property;
import io.swagger.util.Json;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.*;
public class DefaultConverter extends ReflectionUtils implements Converter {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConverter.class);
private Map<String, Model> definitions;
public DefaultConverter(){}
public Object convert(List<String> value, Parameter parameter, Class<?> cls, Map<String, Model> definitions, Iterator<Converter> chain) throws ConversionException {
return coerceValue(value, parameter, cls);
}
public Object coerceValue(List<String> o, Parameter parameter, Class<?> cls) throws ConversionException {
if (o == null || o.size() == 0) {
return null;
}
LOGGER.debug("casting `" + o + "` to " + cls);
if (List.class.equals(cls)) {
if (parameter instanceof SerializableParameter) {
List<Object> output = new ArrayList<Object>();
SerializableParameter sp = (SerializableParameter) parameter;
if (sp.getItems() != null) {
Property inner = sp.getItems();
// TODO: this does not need to be done this way, update the helper method
Parameter innerParam = new QueryParameter().property(inner);
JavaType innerClass = getTypeFromParameter(innerParam, definitions);
for (String obj : o) {
String[] parts = new String[0];
if ("csv".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
parts = obj.split(",");
}
if ("pipes".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
parts = obj.split("|");
}
if ("ssv".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
parts = obj.split(" ");
}
if ("multi".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
parts = new String[1];
parts[0]= obj;
}
for (String p : parts) {
Object ob = cast(p, inner, innerClass);
if (ob != null) {
output.add(ob);
}
}
}
}
return output;
}
} else if (parameter instanceof SerializableParameter) {
TypeFactory tf = Json.mapper().getTypeFactory();
SerializableParameter sp = (SerializableParameter) parameter;
return cast(o.get(0), sp.getItems(), tf.constructType(cls));
}
return null;
}
public Object cast(List<String> o, Parameter parameter, JavaType javaType, Map<String, Model> definitions) throws ConversionException {
if (o == null || o.size() == 0) {
return null;
}
Class<?> cls = javaType.getRawClass();
LOGGER.debug("converting array `" + o + "` to `" + cls + "`");
if (javaType.isArrayType()) {
if (parameter instanceof SerializableParameter) {
List<Object> output = new ArrayList<Object>();
SerializableParameter sp = (SerializableParameter) parameter;
if (sp.getItems() != null) {
if (sp.getItems() instanceof ArrayProperty) {
Property inner = ((ArrayProperty) sp.getItems()).getItems();
// TODO: this does not need to be done this way, update the helper method
Parameter innerParam = new QueryParameter().property(inner);
JavaType innerClass = getTypeFromParameter(innerParam, definitions);
for (String obj : o) {
String[] parts = new String[0];
CSVFormat format = null;
if ("csv".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
format = CSVFormat.DEFAULT;
} else if ("pipes".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
format = CSVFormat.newFormat('|').withQuote('"');
} else if ("ssv".equals(sp.getCollectionFormat()) && !StringUtils.isEmpty(obj)) {
format = CSVFormat.newFormat(' ').withQuote('"');
}
if (format != null) {
try {
for (CSVRecord record : CSVParser.parse(obj, format).getRecords()) {
List<String> it = new ArrayList<String>();
for (Iterator<String> x = record.iterator(); x.hasNext(); ) {
it.add(x.next());
}
parts = it.toArray(new String[it.size()]);
}
} catch (IOException e) {
}
} else {
parts = new String[1];
parts[0] = obj;
}
for (String p : parts) {
Object ob = cast(p, inner, innerClass);
if (ob != null) {
output.add(ob);
}
}
}
}
}
return output;
}
} else if (parameter instanceof SerializableParameter) {
SerializableParameter sp = (SerializableParameter) parameter;
return cast(o.get(0), sp.getItems(), javaType);
}
return null;
}
public Object cast(String o, Property property, JavaType javaType) throws ConversionException {
if (o == null || javaType == null) {
return null;
}
Class<?> cls = javaType.getRawClass();
LOGGER.debug("coercing `" + o + "` to `" + cls + "`");
try {
if (Integer.class.equals(cls)) {
return Integer.parseInt(o);
}
if (Long.class.equals(cls)) {
return Long.parseLong(o);
}
if (Float.class.equals(cls)) {
return Float.parseFloat(o);
}
if (Double.class.equals(cls)) {
return Double.parseDouble(o);
}
if (String.class.equals(cls)) {
return o;
}
if (Boolean.class.equals(cls)) {
if ("1".equals(o)) {
return Boolean.TRUE;
}
if ("0".equals(o)) {
return Boolean.FALSE;
}
return Boolean.parseBoolean(o);
}
if (UUID.class.equals(cls)) {
return UUID.fromString(o);
}
if(LocalDate.class.equals(cls)) {
return LocalDate.parse(o);
}
if(DateTime.class.equals(cls)) {
return DateTime.parse(o);
}
} catch (NumberFormatException e) {
LOGGER.debug("couldn't coerce `" + o + "` to type " + cls);
throw new ConversionException()
.message(new ValidationMessage()
.code(ValidationError.INVALID_FORMAT)
.message("couldn't convert `" + o + "` to type `" + cls + "`"));
} catch (IllegalArgumentException e) {
LOGGER.debug("couldn't coerce `" + o + "` to type " + cls);
throw new ConversionException()
.message(new ValidationMessage()
.code(ValidationError.INVALID_FORMAT)
.message("couldn't convert `" + o + "` to type `" + cls + "`"));
}
return null;
}
}