Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[json-node] Fix NULL value bug with JsonObject #322

Merged
merged 2 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions json-node/src/main/java/io/avaje/json/node/JsonNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.jspecify.annotations.Nullable;

import java.io.Serializable;
import java.util.Optional;

/**
* Represents the core JSON types.
Expand Down Expand Up @@ -107,6 +108,13 @@ default String extract(String path) {
throw new UnsupportedOperationException();
}

/**
* Extract the text from the given path if present else empty.
*/
default Optional<String> extractOrEmpty(String path) {
throw new UnsupportedOperationException();
}

/**
* Extract the text from the given path if present or the given default value.
*
Expand Down Expand Up @@ -172,4 +180,13 @@ default JsonNode extractNode(String path, JsonNode missingValue) {
throw new UnsupportedOperationException();
}

/**
* Extract the node from the given path if present else empty.
*
* @return The node for the given path.
*/
default Optional<JsonNode> extractNodeOrEmpty(String path) {
throw new UnsupportedOperationException();
}

}
17 changes: 13 additions & 4 deletions json-node/src/main/java/io/avaje/json/node/JsonObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import org.jspecify.annotations.Nullable;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.regex.Pattern;

import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -220,6 +217,12 @@ public String extract(String path) {
return node.text();
}

@Override
public Optional<String> extractOrEmpty(String path) {
final var name = find(path);
return name == null ? Optional.empty() : Optional.of(name.text());
}

@Override
public String extract(String path, String missingValue) {
final var name = find(path);
Expand Down Expand Up @@ -272,4 +275,10 @@ public JsonNode extractNode(String path, JsonNode missingValue) {
final var node = find(path);
return node != null ? node : missingValue;
}

@Override
public Optional<JsonNode> extractNodeOrEmpty(String path) {
final var node = find(path);
return Optional.ofNullable(node);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
import io.avaje.json.JsonAdapter;
import io.avaje.json.JsonReader;
import io.avaje.json.JsonWriter;
import io.avaje.json.node.JsonLong;
import io.avaje.json.node.JsonDecimal;

final class DecimalAdapter implements JsonAdapter<JsonLong> {
final class DecimalAdapter implements JsonAdapter<JsonDecimal> {

@Override
public void toJson(JsonWriter writer, JsonLong value) {
writer.value(value.longValue());
public void toJson(JsonWriter writer, JsonDecimal value) {
writer.value(value.decimalValue());
}

@Override
public JsonLong fromJson(JsonReader reader) {
return JsonLong.of(reader.readLong());
public JsonDecimal fromJson(JsonReader reader) {
return JsonDecimal.of(reader.readDecimal());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ObjectAdapter objectAdapter() {
public JsonNode fromJson(JsonReader reader) {
switch (reader.currentToken()) {
case NULL:
reader.isNullValue();
return null;
case BEGIN_ARRAY:
return arrayAdapter.fromJson(reader);
Expand All @@ -55,8 +56,7 @@ public void toJson(JsonWriter writer, JsonNode value) {
writer.nullValue();
return;
}
JsonNode.Type type = value.type();
switch (type) {
switch (value.type()) {
case NULL:
writer.nullValue();
break;
Expand Down
10 changes: 10 additions & 0 deletions json-node/src/test/java/io/avaje/json/node/ExtractNodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ void extract() {

assertThat(missingOther).hasSize(2);
assertThat(missingOther).containsExactly("BOther", "MISSING!");

List<String> missingOther2 =
arrayWithNestedPerson.stream()
.filter(node -> "family".equals(node.extract("type")))
.flatMap(node -> node.extractNodeOrEmpty("person.other").stream())
.map(JsonNode::text)
.collect(Collectors.toList());

assertThat(missingOther2).hasSize(1);
assertThat(missingOther2).containsExactly("BOther");
}

@Test
Expand Down
14 changes: 13 additions & 1 deletion json-node/src/test/java/io/avaje/json/node/JsonObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class JsonObjectTest {

@Test
void of() {
Map<String,JsonNode> map = new LinkedHashMap<>();
Map<String, JsonNode> map = new LinkedHashMap<>();
map.put("name", JsonString.of("foo"));
map.put("other", JsonInteger.of(42));

Expand Down Expand Up @@ -141,6 +141,9 @@ void findNested() {
assertThat(node.extract("person.active", false)).isEqualTo(true);
assertThat(node.extract("person.missing", false)).isEqualTo(false);

assertThat(node.extractOrEmpty("person.missing")).isEmpty();
assertThat(node.extractOrEmpty("person.name")).isNotEmpty().asString().contains("myName");

assertThat(node.extract("address.size", -1)).isEqualTo(42);
assertThat(node.extract("address.junk", -1L)).isEqualTo(99L);
assertThat(node.extract("address.notSize", -1)).isEqualTo(-1);
Expand Down Expand Up @@ -190,4 +193,13 @@ void toPlain() {
assertThat(plainMap.get("name")).isEqualTo("foo");
assertThat(plainMap.get("other")).isEqualTo(Map.of("b", 42));
}

@Test
void nullValuesInMap() {
String s = "{\"a\":1,\"b\":null,\"c\":null,\"d\":4}";
JsonNodeMapper mapper = JsonNodeMapper.builder().build();
JsonObject jsonObject = mapper.fromJsonObject(s);

assertThat(jsonObject.elements().keySet()).containsExactly("a", "b", "c", "d");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import io.avaje.json.JsonAdapter;
import io.avaje.json.JsonReader;
import io.avaje.json.node.*;
import io.avaje.json.simple.SimpleMapper;
import io.avaje.json.stream.JsonStream;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

Expand Down Expand Up @@ -67,9 +69,15 @@ void create_JsonDouble_expect_sameInstance() {

@Test
void create_JsonDecimal_expect_sameInstance() {
JsonAdapter<?> jsonAdapter = mapper.adapter(JsonDecimal.class);
JsonAdapter<JsonDecimal> jsonAdapter = mapper.adapter(JsonDecimal.class);
JsonAdapter<JsonDecimal> adapter = mapper.adapter(JsonDecimal.class);
assertThat(jsonAdapter).isSameAs(adapter);

SimpleMapper.Type<JsonDecimal> type = mapper.type(jsonAdapter);

String asJson1 = type.toJson(JsonDecimal.of(new BigDecimal("23.45")));
assertThat(asJson1).isEqualTo("23.45");
assertThat(type.fromJson(asJson1)).isEqualTo(JsonDecimal.of(new BigDecimal("23.45")));
}

@Test
Expand Down
Loading