Skip to content

Commit

Permalink
Support list of objects for JSON (datafaker-net#693)
Browse files Browse the repository at this point in the history
* Add support list of objects in json transformer

* Add support list of objects in json transformer
  • Loading branch information
RVRhub authored and snuyanzin committed May 7, 2023
1 parent b840846 commit 130830e
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 64 deletions.
51 changes: 30 additions & 21 deletions src/main/java/net/datafaker/transformations/JsonTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public String apply(IN input, Schema<IN, ?> schema) {
if (fields[i] instanceof CompositeField) {
sb.append(apply(input, (CompositeField) fields[i], i));
} else {
value2String(((SimpleField) fields[i]).transform(input), sb);
applyValue(input, sb, ((SimpleField) fields[i]).transform(input));
}
if (i < fields.length - 1) {
sb.append(", ");
Expand Down Expand Up @@ -77,6 +77,35 @@ public String generate(Schema<IN, ?> schema, int limit) {
return limit > 1 ? wrappers[0] + LINE_SEPARATOR + sb + LINE_SEPARATOR + wrappers[1] : sb.toString();
}

private void applyValue(IN input, StringBuilder sb, Object value) {
if (value instanceof Collection<?>) {
sb.append(generate(input,(Collection) value));
} else if (value != null && value.getClass().isArray()) {
sb.append(generate(input, Arrays.asList((Object[]) value)));
} else {
value2String(value, sb);
}
}

private String generate(IN input, Collection<Object> collection) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int i = 0;
for (Object value : collection) {
if (i > 0) {
sb.append(", ");
}
i++;
if (value instanceof CompositeField<?,?>) {
sb.append(apply(input,((CompositeField) value)));
} else {
applyValue(input, sb, value);
}
}
sb.append("]");
return sb.toString();
}

private static void value2String(Object value, StringBuilder sb) {
if (value == null) {
sb.append("null");
Expand All @@ -90,10 +119,6 @@ private static void value2String(Object value, StringBuilder sb) {
|| (value instanceof BigDecimal
&& ((BigDecimal) value).remainder(BigDecimal.ONE).doubleValue() == 0)) {
sb.append(value);
} else if (value instanceof Collection) {
sb.append(generate((Collection) value));
} else if (value.getClass().isArray()) {
sb.append(generate(Arrays.asList((Object[]) value)));
} else {
String val = String.valueOf(value);
boolean toWrap = !val.startsWith("#{json");
Expand All @@ -109,22 +134,6 @@ private static void value2String(Object value, StringBuilder sb) {
}
}

private static String generate(Collection<Object> collection) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int i = 0;
for (Object value : collection) {
if (i > 0) {
sb.append(", ");
}
i++;
value2String(value, sb);
}
sb.append("]");
return sb.toString();
}


private static Map<Character, String> createEscapeMap() {
final Map<Character, String> map = new HashMap<>();
map.put('\\', "\\\\");
Expand Down
118 changes: 102 additions & 16 deletions src/test/java/net/datafaker/formats/JsonTest.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
package net.datafaker.formats;

import static net.datafaker.transformations.Field.compositeField;
import static net.datafaker.transformations.Field.field;
import static net.datafaker.transformations.Transformer.LINE_SEPARATOR;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.jupiter.params.provider.Arguments.of;

import java.math.BigDecimal;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Stream;
import net.datafaker.providers.base.BaseFaker;
import net.datafaker.providers.base.Name;
import net.datafaker.sequence.FakeSequence;
import net.datafaker.transformations.Field;
import net.datafaker.transformations.JsonTransformer;
Expand All @@ -27,6 +12,24 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.math.BigDecimal;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static net.datafaker.transformations.Field.compositeField;
import static net.datafaker.transformations.Field.field;
import static net.datafaker.transformations.Transformer.LINE_SEPARATOR;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
import static org.junit.jupiter.params.provider.Arguments.of;

class JsonTest {
@Test
void testGenerateFromSchemaWithLimit() {
Expand Down Expand Up @@ -255,6 +258,89 @@ private static Stream<Arguments> generateTestJson() {
"{\"key\": \"value\", \"nested\": {\"nestedkey\": \"nestedvalue\"}}"));
}

@Test
void jsonWithDifferentFieldFormatsInOneObjectTest() {
BaseFaker faker = new BaseFaker(new Random(10L));
final int limit = 2;
JsonTransformer<Object> transformer = JsonTransformer.builder().build();

String json = transformer.generate(
faker.collection().minLen(limit).maxLen(limit)
.suppliers(faker::name)
.build(), Schema.<Object, Object>of(
field("text", () -> faker.name().firstName()),
field("array", () ->
faker
.collection()
.suppliers(() -> faker.phoneNumber().phoneNumber())
.maxLen(3)
.generate()
)
));

int numberOfLines = 0;
for (int i = 0; i < json.length(); i++) {
if (json.regionMatches(i, "},", 0, "},".length())) {
numberOfLines++;
}
}
assertThat(numberOfLines).isEqualTo(limit - 1);
}

@Test
void jsonObjectCollectionTest() {
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().build();

String json = transformer.generate(
Schema.of(
field("text", () -> "Mrs. Brian Braun"),
field("objectCollection", () -> Arrays.asList(
compositeField(null, new Field[]{
field("country", () -> "Denmark"),
field("city", () -> "Port Angel")
}
),
compositeField(null, new Field[]{
field("two", () -> "Denmark"),
field("one", () -> "Port Angel")
}
)
)
)
), 1);
assertThat(json).isEqualTo("{\"text\": \"Mrs. Brian Braun\", " +
"\"objectCollection\": [{\"country\": \"Denmark\", \"city\": \"Port Angel\"}, {\"two\": \"Denmark\", \"one\": \"Port Angel\"}]}");
}

@Test
void jsonCollectionOfCollectionsTest() {
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().build();

String json = transformer.generate(
Schema.of(
field("text", () -> "Mrs. Brian Braun"),
field("objectCollection", () -> Arrays.asList(
Arrays.asList(
Arrays.asList(
compositeField(null, new Field[]{
field("country", () -> "Denmark"),
field("city", () -> "Port Angel")
}
),
compositeField(null, new Field[]{
field("two", () -> "Denmark"),
field("one", () -> "Port Angel")
}
)
)
)
)
)
), 1);
assertThat(json).isEqualTo("{\"text\": \"Mrs. Brian Braun\", " +
"\"objectCollection\": [[[{\"country\": \"Denmark\", \"city\": \"Port Angel\"}, {\"two\": \"Denmark\", \"one\": \"Port Angel\"}]]]}");
}

private static Map.Entry<Supplier<String>, Supplier<Object>> entry(
Supplier<String> key, Supplier<Object> value) {
return new AbstractMap.SimpleEntry<>(key, value);
Expand Down
63 changes: 36 additions & 27 deletions src/test/java/net/datafaker/sequence/FakeCollectionTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package net.datafaker.sequence;

import net.datafaker.AbstractFakerTest;
import net.datafaker.formats.Format;
import net.datafaker.providers.base.Address;
import net.datafaker.providers.base.BaseFaker;
import net.datafaker.providers.base.Name;
import net.datafaker.providers.base.Number;
import net.datafaker.transformations.CompositeField;
import net.datafaker.transformations.CsvTransformer;
import net.datafaker.transformations.Field;
import net.datafaker.transformations.JsonTransformer;
import net.datafaker.transformations.Schema;
import org.junit.jupiter.api.RepeatedTest;
Expand All @@ -18,6 +20,7 @@
import java.util.Random;
import java.util.function.Supplier;

import static net.datafaker.transformations.Field.compositeField;
import static net.datafaker.transformations.Field.field;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand Down Expand Up @@ -222,36 +225,42 @@ void toJson() {
@Test
void toNestedJson() {
final int limit = 2;
final String json =
Format.toJson(faker.collection()
.suppliers(faker::name)
.maxLen(limit)
.minLen(limit)
.build())
.set("primaryAddress", Format.toJson()
.set("country", () -> faker.address().country())
.set("city", () -> faker.address().city())
.set("zipcode", () -> faker.address().zipCode())
.set("streetAddress", () -> faker.address().streetAddress())
.build())
.set("secondaryAddresses", Format.toJson(faker.<Address>collection()
.suppliers(faker::address)
.maxLen(1)
.minLen(1)
.build())
.set("country", Address::country)
.set("city", Address::city)
.set("zipcode", Address::zipCode)
.set("streetAddress", Address::streetAddress)
.build())
.set("phones", name -> faker.collection().suppliers(() -> faker.phoneNumber().phoneNumber()).maxLen(3).build().get())
.build()
.generate();
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().formattedAs(JsonTransformer.JsonTransformerBuilder.FormattedAs.JSON_ARRAY).build();

FakeSequence<CompositeField<Address, String>> secondaryAddresses =
faker.<CompositeField<Address, String>>collection()
.suppliers(() ->
compositeField(null, new Field[]{
field("country", () -> faker.address().country()),
field("city", () -> faker.address().city()),
field("zipcode", () -> faker.address().zipCode()),
field("streetAddress", () -> faker.address().streetAddress())
})
)
.maxLen(1)
.minLen(1)
.build();

String json = transformer.generate(
faker.<Name>collection().minLen(limit).maxLen(limit)
.suppliers(faker::name)
.build(),
Schema.of(
compositeField("primaryAddress", new Field[]{
field("country", () -> faker.address().country()),
field("city", () -> faker.address().city()),
field("zipcode", () -> faker.address().zipCode()),
field("streetAddress", () -> faker.address().streetAddress())
}),
field("secondaryAddresses", secondaryAddresses::get),
field("phones", name -> faker.collection().suppliers(() -> faker.phoneNumber().phoneNumber()).maxLen(3).build().get())
));


System.out.println(json);
int numberOfLines = 0;
for (int i = 0; i < json.length(); i++) {
if (json.regionMatches(i, System.lineSeparator(), 0, System.lineSeparator().length())) {
if (json.regionMatches(i, "}," + System.lineSeparator(), 0, ("}," + System.lineSeparator()).length())) {
numberOfLines++;
}
}
Expand Down

0 comments on commit 130830e

Please sign in to comment.