diff --git a/plugin-parent/json-stream/pom.xml b/plugin-parent/json-stream/pom.xml index 40d6ba3aaf..6a18513af5 100644 --- a/plugin-parent/json-stream/pom.xml +++ b/plugin-parent/json-stream/pom.xml @@ -120,6 +120,11 @@ junit + + org.mockito + mockito-core + + org.hamcrest hamcrest-core diff --git a/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/JsonCollector.java b/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/JsonCollector.java index b2d5a31866..98e37e00fc 100644 --- a/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/JsonCollector.java +++ b/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/JsonCollector.java @@ -17,8 +17,8 @@ package com.speedment.plugins.json; import com.speedment.plugins.json.internal.JsonCollectorImpl; -import java.util.List; import static java.util.Objects.requireNonNull; +import java.util.StringJoiner; import java.util.stream.Collector; import static java.util.stream.Collectors.joining; @@ -26,8 +26,7 @@ * A specialized java {@link Collector} that converts streams of Speedment * entities into JSON arrays. *

- * Example usage: - * + * Example usage: * app.getOrThrow(EmployeeManager.class).stream() * .filter(Employee.AGE.greaterThan(35)) * .filter(Employee.NAME.startsWith("B")) @@ -35,29 +34,26 @@ * jsonComponent.allOf(employees) * )); * - * + * * @param the entity type - * + * * @author Emil Forslund - * @since 1.0.0 + * @since 1.0.0 */ -public interface JsonCollector extends Collector, String> { +public interface JsonCollector extends Collector { /** * Returns a collector that calls the specified encoder for each element in - * the stream and joins the resuling stream separated by commas and - * surrounded by square brackets. Each element is also formatted using the + * the stream and joins the resulting stream separated by commas and + * surrounded by square brackets. Each element is also formatted using the * specified {@link JsonEncoder}. * - * @param the type of the stream - * @param encoder the enocder to use - * @return the json string + * @param the type of the stream + * @param encoder the enocder to use + * @return the json string */ static JsonCollector toJson(JsonEncoder encoder) { requireNonNull(encoder); - - return JsonCollectorImpl.collect( - encoder::apply, l -> "[" + l.stream().collect(joining(",")) + "]" - ); + return JsonCollectorImpl.collect(encoder::apply); } } diff --git a/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/internal/JsonCollectorImpl.java b/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/internal/JsonCollectorImpl.java index 27caedb3d2..ad95d35f7a 100644 --- a/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/internal/JsonCollectorImpl.java +++ b/plugin-parent/json-stream/src/main/java/com/speedment/plugins/json/internal/JsonCollectorImpl.java @@ -17,63 +17,57 @@ package com.speedment.plugins.json.internal; import com.speedment.plugins.json.JsonCollector; - import java.util.*; +import static java.util.Objects.requireNonNull; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; -import static java.util.Objects.requireNonNull; -import static java.util.stream.Collector.Characteristics.CONCURRENT; - /** * - * @author Emil Forslund - * @since 1.0.0 + * @author Emil Forslund + * @param type of the entity + * @since 1.0.0 */ public final class JsonCollectorImpl implements JsonCollector { - - public static JsonCollector collect(Function converter, Function, String> merger) { - return new JsonCollectorImpl<>(converter, merger); + + public static JsonCollector collect(Function converter) { + return new JsonCollectorImpl<>(converter); } - + @Override - public Supplier> supplier() { - return () -> Collections.synchronizedList(new ArrayList<>()); + public Supplier supplier() { + return () -> new StringJoiner(",", "[", "]"); } @Override - public BiConsumer, ENTITY> accumulator() { - return (l, t) -> { - l.add(converter.apply(t)); - }; + public BiConsumer accumulator() { + return (sj, t) -> sj.add(converter.apply(t)); } @Override - public BinaryOperator> combiner() { - return (l1, l2) -> { - l1.addAll(l2); - return l1; - }; + public BinaryOperator combiner() { + return StringJoiner::merge; } @Override - public Function, String> finisher() { - return merger::apply; + public Function finisher() { + return StringJoiner::toString; } + private static final Set CHARACTERISTICS + = Collections.unmodifiableSet(EnumSet.noneOf(Characteristics.class)); + @Override public Set characteristics() { - return EnumSet.of(CONCURRENT); + return CHARACTERISTICS; } - - private JsonCollectorImpl(Function converter, Function, String> merger) { + + private JsonCollectorImpl(Function converter) { this.converter = requireNonNull(converter); - this.merger = requireNonNull(merger); } - + private final Function converter; - private final Function, String> merger; -} \ No newline at end of file +} diff --git a/plugin-parent/json-stream/src/test/java/com/speedment/plugins/json/internal/JsonComponentImplTest.java b/plugin-parent/json-stream/src/test/java/com/speedment/plugins/json/internal/JsonComponentImplTest.java new file mode 100644 index 0000000000..84d105a3b6 --- /dev/null +++ b/plugin-parent/json-stream/src/test/java/com/speedment/plugins/json/internal/JsonComponentImplTest.java @@ -0,0 +1,200 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.speedment.plugins.json.internal; + +import com.speedment.common.injector.Injector; +import com.speedment.common.injector.exception.NoDefaultConstructorException; +import com.speedment.plugins.json.JsonBundle; +import com.speedment.plugins.json.JsonComponent; +import com.speedment.plugins.json.JsonEncoder; +import com.speedment.runtime.config.Project; +import com.speedment.runtime.config.identifier.ColumnIdentifier; +import com.speedment.runtime.config.identifier.TableIdentifier; +import com.speedment.runtime.config.internal.ProjectImpl; +import com.speedment.runtime.core.component.ProjectComponent; +import com.speedment.runtime.core.manager.Manager; +import com.speedment.runtime.field.IntField; +import com.speedment.runtime.field.StringField; +import com.speedment.runtime.typemapper.TypeMapper; +import java.util.HashMap; +import java.util.Map; +import static java.util.Objects.requireNonNull; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.Before; +import org.junit.Test; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * + * @author Per Minborg + */ +public class JsonComponentImplTest { + + private JsonComponent jsonComponent; + private Manager persons; + + @Before + @SuppressWarnings("unchecked") + public void init() { + jsonComponent = newComponent(); + persons = (Manager) mock(Manager.class); + final Stream personStream = IntStream.range(0, 8).mapToObj(i -> new Person(i)); + when(persons.stream()).thenReturn(personStream); + when(persons.fields()).thenReturn(Stream.of(Person.ID, Person.NAME)); + } + + @Test + public void testNoneOf() { + final JsonEncoder result = jsonComponent.noneOf(persons); + final String json = persons.stream().collect(result.collector()); + System.out.println(json); + } + +// @Test +// public void testAllOf() { +// System.out.println("allOf"); +// final JsonEncoder result = jsonComponent.allOf(persons); +// final String json = persons.stream().collect(result.collector()); +// System.out.println(json); +// } +// +// @Test +// public void testOf() { +// System.out.println("of"); +// @SuppressWarnings("unchecked") +// final JsonEncoder result = jsonComponent.of(persons, Person.ID, Person.NAME); +// final String json = persons.stream().collect(result.collector()); +// System.out.println(json); +// } + + private static class Person { + + public static IntField ID = IntField.create( + Identifier.ID, + Person::getId, + Person::setId, + TypeMapper.primitive(), + true + ); + /** + * This Field corresponds to the {@link Human} field that can be + * obtained using the {@link Human#getName()} method. + */ + public static StringField NAME = StringField.create( + Identifier.NAME, + Person::getName, + Person::setName, + TypeMapper.identity(), + false + ); + + private int id; + private String name; + + public Person(int id) { + this.id = id; + this.name = "name" + id; + } + + public int getId() { + return id; + } + + public Person setId(int id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public Person setName(String name) { + this.name = name; + return this; + } + + enum Identifier implements ColumnIdentifier { + + ID("id"), + NAME("name"); + + private final String columnName; + private final TableIdentifier tableIdentifier; + + Identifier(String columnName) { + this.columnName = columnName; + this.tableIdentifier = TableIdentifier.of(getDbmsName(), + getSchemaName(), + getTableName()); + } + + @Override + public String getDbmsName() { + return "db0"; + } + + @Override + public String getSchemaName() { + return "schema"; + } + + @Override + public String getTableName() { + return "person"; + } + + @Override + public String getColumnName() { + return this.columnName; + } + + @Override + public TableIdentifier asTableIdentifier() { + return this.tableIdentifier; + } + } + + } + + private JsonComponent newComponent() { + try { + Injector injector = Injector.builder() + .withComponent(MyProjectComponent.class) + .withBundle(JsonBundle.class) + .build(); + + return injector.getOrThrow(JsonComponent.class); + + } catch (InstantiationException | NoDefaultConstructorException e) { + throw new RuntimeException(e); + } + } + + private static class MyProjectComponent implements ProjectComponent { + + private Project project; + + public MyProjectComponent() { + final Project project = mock(Project.class); + setProject(project); + } + + @Override + public Project getProject() { + return project; + } + + @Override + public void setProject(Project project) { + this.project = requireNonNull(project); + } + + } + +}