simdjson/simdjson-java

Any function similar to jackson's objectMapper.readValue?

Closed this issue · 6 comments

When using jackson, one can use

JsonFactory jsonFactory = new JsonFactory();
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
objectMapper.readValue(jsonString, TYPE);

to transfer json to Object or using writeValueAsString vice versa.

I'd like to know is there any function in simdjson can do the same thing?

Currently, there is no such function. However, there are plans to add it.

Thx. Looking forward to this feature.

Additionally, I saw toString() in JsonValue.java:

@Override
public String toString() {
    switch (tape.getType(tapeIdx)) {
        case INT64 -> {
            return String.valueOf(asLong());
        }
        case DOUBLE -> {
            return String.valueOf(asDouble());
        }
        case TRUE_VALUE, FALSE_VALUE -> {
            return String.valueOf(asBoolean());
        }
        case STRING -> {
            return asString();
        }
        case NULL_VALUE -> {
            return "null";
        }
        case START_OBJECT -> {
            return "<object>";
        }
        case START_ARRAY -> {
            return "<array>";
        }
        default -> {
            return "unknown";
        }
    }
}

IMHO START_OBJECT is the part I mentioned before. But how about array? If we have elements in json which type is array, we cannot use get to get the value of the array?

Do you mean something like this:

JsonValue json = parser.parse(...);
JsonValue[] array = json.getArray();

?

If that's the case, then currently it's not available. The only option is to use JsonValue::arrayIterator.

for toString currently I'm using this workaround

void stringify(JsonValue v, StringBuilder w) {
        if (v.isArray()) {
            w.append('[');
            final var iter = v.arrayIterator();
            while (iter.hasNext()) {
                final var element = iter.next();
                stringify(element, w);
            }
            w.append('[');
        } else if (v.isObject()) {
            w.append('{');
            final var iter = v.objectIterator();
            boolean first = true;
            while (iter.hasNext()) {
                if (!first) w.append(',');
                final var element = iter.next();
                w.append('\"');
                w.append(element.getKey());
                w.append('\"');
                w.append(':');
                stringify(element.getValue(), w);
                first = false;
            }
            w.append('}');
        } else if (v.isString()) {
            w.append('\"');
            // may try to find vectorized version
            w.append(com.fasterxml.jackson.core.util.BufferRecyclers.getJsonStringEncoder().quoteAsString(v.asString()));
            w.append('\"');
        } else {
            w.append(v);
        }
    }

so you can use it like

            JsonValue jsonNode = entry.getValue();
            if (jsonNode != null && !jsonNode.isNull()) {
                final var sb = new StringBuilder();
                stringify(jsonNode, sb);
                
                // ... use sb
            }

but this is slow. I wonder if there is a way to use stringBuffer or buffer of the JsonNode instead to achieve the same effect?

I'm using the similar workaround as you by modifying toString() @andyglow

@Override
    public String toString() {
        switch (tape.getType(tapeIdx)) {
            case INT64 -> {
                return String.valueOf(asLong());
            }
            case DOUBLE -> {
                return String.valueOf(asDouble());
            }
            case TRUE_VALUE, FALSE_VALUE -> {
                return String.valueOf(asBoolean());
            }
            case STRING -> {
                return asString();
            }
            case NULL_VALUE -> {
                return "null";
            }
            case START_OBJECT -> {
                Iterator<Map.Entry<String, JsonValue>> it = this.objectIterator();
                String result = "{";
                boolean first = true;
                while (it.hasNext()) {
                    if(!first)
                        result += ", ";
                    Map.Entry<String, JsonValue> field = it.next();
                    result += field.getKey() + "=" + field.getValue().toString();
                    first = false;
                }
                result += "}";
                return result;
            }
            case START_ARRAY -> {
                Iterator<JsonValue> it = this.arrayIterator();
                String result = "[";
                boolean first = true;
                while (it.hasNext()) {
                    if(!first)
                        result += ", ";
                    JsonValue field = it.next();
                    result += field.toString();
                    first = false;
                }
                result += "]";
                return result;
            }
            default -> {
                return "unknown";
            }
        }
    }

I think you have a little typo mistake, line 9 of stringify() should be w.append(']');