class TypeUtils {

    public static Object coerce(Field field, Object origVal)
    {
        if (origVal == null) {
            return origVal;
        }

        if (origVal instanceof ObjectId) {
            return origVal.toString();
        }

        ArrowType arrowType = field.getType();
        Types.MinorType minorType = Types.getMinorTypeForArrowType(arrowType);

        switch (minorType) {
            case VARCHAR:
                if (origVal instanceof String) {
                    return origVal;
                }
                else {
                    return String.valueOf(origVal);
                }
            case FLOAT8:
                if (origVal instanceof Integer) {
                    return Double.valueOf((int) origVal);
                }
                else if (origVal instanceof Float) {
                    return Double.valueOf((float) origVal);
                }
                return origVal;
            case FLOAT4:
                if (origVal instanceof Integer) {
                    return Float.valueOf((int) origVal);
                }
                else if (origVal instanceof Double) {
                    return ((Double) origVal).floatValue();
                }
                return origVal;
            case INT:
                if (origVal instanceof Float) {
                    return ((Float) origVal).intValue();
                }
                else if (origVal instanceof Double) {
                    return ((Double) origVal).intValue();
                }
                return origVal;
            case DATEMILLI:
                if (origVal instanceof BsonTimestamp) {
                    return new Date(((BsonTimestamp) origVal).getTime() * 1_000);
                }
                return origVal;
            default:
                return origVal;
        }
    }

    private  TypeUtils();

}