From a4d768763b9275d717c92bdf19ea93f4186dfd15 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 6 Dec 2018 15:23:13 +0400 Subject: [PATCH 001/139] Vector class example --- .../com/baeldung/java/list/VectorExample.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java diff --git a/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java b/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java new file mode 100644 index 0000000000..38736390ca --- /dev/null +++ b/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java @@ -0,0 +1,21 @@ +package com.baeldung.java.list; + +import java.util.Enumeration; +import java.util.Vector; + +public class VectorExample { + + public static void main(String[] args) { + + Vector vector = new Vector<>(); + vector.add("baeldung"); + vector.add("Vector"); + vector.add("example"); + + Enumeration e = vector.elements(); + while(e.hasMoreElements()){ + System.out.println(e.nextElement()); + } + } + +} From c52862fdd42d370f6a9ac923cb9a43ad2a29696d Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 13 Dec 2018 17:23:25 +0400 Subject: [PATCH 002/139] Vector class JMH --- .../baeldung/performance/ArrayListBenchmark.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java index dddd85007d..5c3f7531e3 100644 --- a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java +++ b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java @@ -17,6 +17,7 @@ public class ArrayListBenchmark { public static class MyState { List employeeList = new ArrayList<>(); + Vector employeeVector = new Vector<>(); //LinkedList employeeList = new LinkedList<>(); long iterations = 100000; @@ -29,9 +30,11 @@ public class ArrayListBenchmark { public void setUp() { for (long i = 0; i < iterations; i++) { employeeList.add(new Employee(i, "John")); + employeeVector.add(new Employee(i, "John")); } employeeList.add(employee); + employeeVector.add(employee); employeeIndex = employeeList.indexOf(employee); } } @@ -55,16 +58,20 @@ public class ArrayListBenchmark { public Employee testGet(ArrayListBenchmark.MyState state) { return state.employeeList.get(state.employeeIndex); } + @Benchmark + public Employee testVectorGet(ArrayListBenchmark.MyState state) { + return state.employeeVector.get(state.employeeIndex); + } @Benchmark public boolean testRemove(ArrayListBenchmark.MyState state) { return state.employeeList.remove(state.employee); } -// @Benchmark -// public void testAdd(ArrayListBenchmark.MyState state) { -// state.employeeList.add(new Employee(state.iterations + 1, "John")); -// } + @Benchmark + public void testAdd(ArrayListBenchmark.MyState state) { + state.employeeList.add(new Employee(state.iterations + 1, "John")); + } public static void main(String[] args) throws Exception { Options options = new OptionsBuilder() From cf56b33b9bc2890f419e529ffd37dea4ec5c38ae Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:43:32 +0100 Subject: [PATCH 003/139] BAEL-2435 Update pom file -Add description -Change parent to parent-boot-2 to leverage a spring boot start up approach -Replace core dependency for axon-spring-boot-autoconfigure excluding axon-server as we cant start that up for this use case -Add spring-boot-autoconfigure dependency -Adjust the axon version to 4.0.3 --- axon/pom.xml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/axon/pom.xml b/axon/pom.xml index c643ea9e57..bb7839f150 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -4,29 +4,45 @@ 4.0.0 axon axon - + Basic Axon Framework with Spring Boot configuration tutorial + - parent-modules com.baeldung - 1.0.0-SNAPSHOT + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + org.axonframework + axon-spring-boot-autoconfigure + ${axon.version} + + + org.axonframework + axon-server-connector + + + + org.axonframework axon-test ${axon.version} test + - org.axonframework - axon-core - ${axon.version} + org.springframework.boot + spring-boot-autoconfigure + 2.1.1.RELEASE + compile - 3.0.2 + 4.0.3 \ No newline at end of file From bd4881d4787cea8ee7f78309e956a7363d14c1b3 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:47:23 +0100 Subject: [PATCH 004/139] BAEL-2435 Update Aggregate in regards to latest axon version -Replace old import statements for the new locations -Mark the aggregate as @Aggregate to make it autowired through the spring boot starter -Move all command handlers/decision making functions to the top of the file -Rename the command handler to `handle` as a best practice for command handlers -Use @EventSourcingHandler i.o. @EventHandler as a best practice for event handlers in Aggregates, as those only are used to 'source' the aggregate -Update test case according to latest standards --- .../axon/aggregates/MessagesAggregate.java | 26 ++++++++++--------- .../MessagesAggregateIntegrationTest.java | 21 +++++++-------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java index e762604b74..d95dd81df9 100644 --- a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java @@ -1,16 +1,18 @@ package com.baeldung.axon.aggregates; +import static org.axonframework.modelling.command.AggregateLifecycle.apply; + +import org.axonframework.commandhandling.CommandHandler; +import org.axonframework.eventsourcing.EventSourcingHandler; +import org.axonframework.modelling.command.AggregateIdentifier; +import org.axonframework.spring.stereotype.Aggregate; + import com.baeldung.axon.commands.CreateMessageCommand; import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; -import org.axonframework.commandhandling.CommandHandler; -import org.axonframework.commandhandling.model.AggregateIdentifier; -import org.axonframework.eventhandling.EventHandler; - -import static org.axonframework.commandhandling.model.AggregateLifecycle.apply; - +@Aggregate public class MessagesAggregate { @AggregateIdentifier @@ -24,13 +26,13 @@ public class MessagesAggregate { apply(new MessageCreatedEvent(command.getId(), command.getText())); } - @EventHandler + @CommandHandler + public void handle(MarkReadMessageCommand command) { + apply(new MessageReadEvent(id)); + } + + @EventSourcingHandler public void on(MessageCreatedEvent event) { this.id = event.getId(); } - - @CommandHandler - public void markRead(MarkReadMessageCommand command) { - apply(new MessageReadEvent(id)); - } } \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java index ad099d2c2b..dc008dcd78 100644 --- a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java @@ -1,29 +1,28 @@ package com.baeldung.axon; +import java.util.UUID; + +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.*; + import com.baeldung.axon.aggregates.MessagesAggregate; import com.baeldung.axon.commands.CreateMessageCommand; import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; -import org.axonframework.test.aggregate.AggregateTestFixture; -import org.axonframework.test.aggregate.FixtureConfiguration; -import org.junit.Before; -import org.junit.Test; - -import java.util.UUID; public class MessagesAggregateIntegrationTest { private FixtureConfiguration fixture; @Before - public void setUp() throws Exception { - fixture = new AggregateTestFixture(MessagesAggregate.class); - + public void setUp() { + fixture = new AggregateTestFixture<>(MessagesAggregate.class); } @Test - public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() throws Exception { + public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() { String eventText = "Hello, how is your day?"; String id = UUID.randomUUID().toString(); fixture.given() @@ -32,7 +31,7 @@ public class MessagesAggregateIntegrationTest { } @Test - public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() throws Exception { + public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() { String id = UUID.randomUUID().toString(); fixture.given(new MessageCreatedEvent(id, "Hello :-)")) From 11b1112771d6327560debdf0c06306103c5bf7ac Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:48:10 +0100 Subject: [PATCH 005/139] BAEL-2435 Update the event handler Change the event handler to become a spring service, as this way Axon will automatically pick it up as an event handling component --- .../baeldung/axon/eventhandlers/MessagesEventHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java index 3e51e19c4e..d7ac115a16 100644 --- a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java @@ -1,10 +1,12 @@ package com.baeldung.axon.eventhandlers; -import com.baeldung.axon.events.MessageReadEvent; -import com.baeldung.axon.events.MessageCreatedEvent; import org.axonframework.eventhandling.EventHandler; +import org.springframework.stereotype.Service; +import com.baeldung.axon.events.MessageCreatedEvent; +import com.baeldung.axon.events.MessageReadEvent; +@Service public class MessagesEventHandler { @EventHandler From 3553fb750685f94af4f8dbdeaffb0a140497556a Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:49:30 +0100 Subject: [PATCH 006/139] BAEL-2435 Update commands and events -Change TargetAggregateIdentifier import statement to the new location -Add equals/hashcode as best practice for commands and events -Add description -Change parent to parent-boot-2 to leverage a spring boot start up approach --- .../axon/commands/CreateMessageCommand.java | 28 +++++++++++++++---- .../axon/commands/MarkReadMessageCommand.java | 26 ++++++++++++++--- .../axon/events/MessageCreatedEvent.java | 27 +++++++++++++++--- .../axon/events/MessageReadEvent.java | 25 +++++++++++++++-- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java index d0651bf12e..70d2e46480 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java @@ -1,24 +1,42 @@ package com.baeldung.axon.commands; +import java.util.Objects; -import org.axonframework.commandhandling.TargetAggregateIdentifier; +import org.axonframework.modelling.command.TargetAggregateIdentifier; public class CreateMessageCommand { - + @TargetAggregateIdentifier private final String id; private final String text; - + public CreateMessageCommand(String id, String text) { this.id = id; this.text = text; } - + public String getId() { return id; } - + public String getText() { return text; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CreateMessageCommand that = (CreateMessageCommand) o; + return Objects.equals(id, that.id) && Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + return Objects.hash(id, text); + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java index e66582d9ec..f7d911d65b 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java @@ -1,18 +1,36 @@ package com.baeldung.axon.commands; +import java.util.Objects; -import org.axonframework.commandhandling.TargetAggregateIdentifier; +import org.axonframework.modelling.command.TargetAggregateIdentifier; public class MarkReadMessageCommand { - + @TargetAggregateIdentifier private final String id; - + public MarkReadMessageCommand(String id) { this.id = id; } - + public String getId() { return id; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarkReadMessageCommand that = (MarkReadMessageCommand) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java index 3c9aac5ed8..e638a2a94d 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java @@ -1,20 +1,39 @@ package com.baeldung.axon.events; +import java.util.Objects; + public class MessageCreatedEvent { - + private final String id; private final String text; - + public MessageCreatedEvent(String id, String text) { this.id = id; this.text = text; } - + public String getId() { return id; } - + public String getText() { return text; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageCreatedEvent that = (MessageCreatedEvent) o; + return Objects.equals(id, that.id) && Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + return Objects.hash(id, text); + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java index 57bfc8e19e..e362599bb3 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java +++ b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java @@ -1,14 +1,33 @@ package com.baeldung.axon.events; +import java.util.Objects; + public class MessageReadEvent { - + private final String id; - + public MessageReadEvent(String id) { this.id = id; } - + public String getId() { return id; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageReadEvent that = (MessageReadEvent) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } \ No newline at end of file From 3e3210a8038b4c9453d1958714119243d0c732d3 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:52:54 +0100 Subject: [PATCH 007/139] BAEL-2435 Change aggregate package -Change aggregate package to commandmodel package per best practice -Move the aggregate test to the same package for the test directory --- .../axon/{aggregates => commandmodel}/MessagesAggregate.java | 2 +- .../{ => commandmodel}/MessagesAggregateIntegrationTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename axon/src/main/java/com/baeldung/axon/{aggregates => commandmodel}/MessagesAggregate.java (96%) rename axon/src/test/java/com/baeldung/axon/{ => commandmodel}/MessagesAggregateIntegrationTest.java (94%) diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java similarity index 96% rename from axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java rename to axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index d95dd81df9..b2c3a0a0b6 100644 --- a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.aggregates; +package com.baeldung.axon.commandmodel; import static org.axonframework.modelling.command.AggregateLifecycle.apply; diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java similarity index 94% rename from axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java index dc008dcd78..96bb2cf3b7 100644 --- a/axon/src/test/java/com/baeldung/axon/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.axon; +package com.baeldung.axon.commandmodel; import java.util.UUID; @@ -6,7 +6,6 @@ import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.junit.*; -import com.baeldung.axon.aggregates.MessagesAggregate; import com.baeldung.axon.commands.CreateMessageCommand; import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; From 00b297a4d0a21282d13b7c7a41544aa56b782b59 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:53:43 +0100 Subject: [PATCH 008/139] BAEL-2435 Rename aggregate test Rename aggregate test from MessagesAggregateIntegrationTest to MessagesAggregateTest, as it's not an integration test but a regular unit test --- ...AggregateIntegrationTest.java => MessagesAggregateTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/test/java/com/baeldung/axon/commandmodel/{MessagesAggregateIntegrationTest.java => MessagesAggregateTest.java} (96%) diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java similarity index 96% rename from axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 96bb2cf3b7..30914e3fd3 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateIntegrationTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -11,7 +11,7 @@ import com.baeldung.axon.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; -public class MessagesAggregateIntegrationTest { +public class MessagesAggregateTest { private FixtureConfiguration fixture; From aaf2ef22276bc1b3f0bc64f3acbf0d3582afb9c9 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:54:07 +0100 Subject: [PATCH 009/139] BAEL-2435 Change eventhandlers package Change eventhandlers package to querymodel package per best practices --- .../{eventhandlers => querymodel}/MessagesEventHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/main/java/com/baeldung/axon/{eventhandlers => querymodel}/MessagesEventHandler.java (93%) diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java similarity index 93% rename from axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java rename to axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java index d7ac115a16..d93fe03941 100644 --- a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.eventhandlers; +package com.baeldung.axon.querymodel; import org.axonframework.eventhandling.EventHandler; import org.springframework.stereotype.Service; From 96945027a14e5bf1a9b72ddfac7e38e1c170af74 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:55:28 +0100 Subject: [PATCH 010/139] BAEL-2435 Change command message package Change the package of the command messages to coreapi.commands to signal that the commands are part of the API you'd share with the outside --- .../com/baeldung/axon/commandmodel/MessagesAggregate.java | 4 ++-- .../axon/{ => coreapi}/commands/CreateMessageCommand.java | 2 +- .../axon/{ => coreapi}/commands/MarkReadMessageCommand.java | 2 +- .../com/baeldung/axon/commandmodel/MessagesAggregateTest.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/commands/CreateMessageCommand.java (95%) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/commands/MarkReadMessageCommand.java (94%) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index b2c3a0a0b6..60b5c7c94e 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -7,8 +7,8 @@ import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.spring.stereotype.Aggregate; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java similarity index 95% rename from axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java rename to axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java index 70d2e46480..fd03d6b269 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.commands; +package com.baeldung.axon.coreapi.commands; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java similarity index 94% rename from axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java rename to axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java index f7d911d65b..ec68a380f8 100644 --- a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.commands; +package com.baeldung.axon.coreapi.commands; import java.util.Objects; diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 30914e3fd3..3bb7fdc9a2 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -6,8 +6,8 @@ import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.junit.*; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.events.MessageCreatedEvent; import com.baeldung.axon.events.MessageReadEvent; From 2b07c0364d5f7cd1e4d8f178bd99c968e89324c2 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 14:56:23 +0100 Subject: [PATCH 011/139] BAEL-2435 Change event message package Change the package of the event messages to coreapi.events to signal that the events are part of the API you'd share with the outside --- .../com/baeldung/axon/commandmodel/MessagesAggregate.java | 4 ++-- .../axon/{ => coreapi}/events/MessageCreatedEvent.java | 2 +- .../baeldung/axon/{ => coreapi}/events/MessageReadEvent.java | 2 +- .../com/baeldung/axon/querymodel/MessagesEventHandler.java | 4 ++-- .../com/baeldung/axon/commandmodel/MessagesAggregateTest.java | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/events/MessageCreatedEvent.java (94%) rename axon/src/main/java/com/baeldung/axon/{ => coreapi}/events/MessageReadEvent.java (93%) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java index 60b5c7c94e..1ab9501617 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java @@ -9,8 +9,8 @@ import org.axonframework.spring.stereotype.Aggregate; import com.baeldung.axon.coreapi.commands.CreateMessageCommand; import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; @Aggregate public class MessagesAggregate { diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java similarity index 94% rename from axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java rename to axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java index e638a2a94d..debf383771 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.events; +package com.baeldung.axon.coreapi.events; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java similarity index 93% rename from axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java rename to axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java index e362599bb3..f90bfb054e 100644 --- a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java @@ -1,4 +1,4 @@ -package com.baeldung.axon.events; +package com.baeldung.axon.coreapi.events; import java.util.Objects; diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java index d93fe03941..6988d40a53 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java @@ -3,8 +3,8 @@ package com.baeldung.axon.querymodel; import org.axonframework.eventhandling.EventHandler; import org.springframework.stereotype.Service; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; @Service public class MessagesEventHandler { diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java index 3bb7fdc9a2..1a95726c83 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java @@ -8,8 +8,8 @@ import org.junit.*; import com.baeldung.axon.coreapi.commands.CreateMessageCommand; import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.events.MessageCreatedEvent; -import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.coreapi.events.MessageCreatedEvent; +import com.baeldung.axon.coreapi.events.MessageReadEvent; public class MessagesAggregateTest { From e731b95ffbb596d3674bd3e6de724e35dcf4a7df Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:01:29 +0100 Subject: [PATCH 012/139] BAEL-2435 Rename unit test class Rename unit test class to actual contain 'UnitTest' per the defined standards --- ...essagesAggregateTest.java => MessagesAggregateUnitTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename axon/src/test/java/com/baeldung/axon/commandmodel/{MessagesAggregateTest.java => MessagesAggregateUnitTest.java} (97%) diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java similarity index 97% rename from axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java rename to axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java index 1a95726c83..46357ddff8 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java @@ -11,7 +11,7 @@ import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; import com.baeldung.axon.coreapi.events.MessageCreatedEvent; import com.baeldung.axon.coreapi.events.MessageReadEvent; -public class MessagesAggregateTest { +public class MessagesAggregateUnitTest { private FixtureConfiguration fixture; From fe30c44889111ccaa94b4e69d49fc800b21c5d90 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:15:23 +0100 Subject: [PATCH 013/139] BAEL-2435 Add a GUI -Add spring-boot-starter-web to support rest endpoints -Add a rest endpoint to spoof some form of UI to publish a message, as the old main will no longer publish the commands upon start up --- axon/pom.xml | 5 ++++ .../axon/gui/MessagesRestEndpoint.java | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java diff --git a/axon/pom.xml b/axon/pom.xml index bb7839f150..639c50d70b 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -39,6 +39,11 @@ 2.1.1.RELEASE compile + + + org.springframework.boot + spring-boot-starter-web + diff --git a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java new file mode 100644 index 0000000000..ddbc3e2fc5 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java @@ -0,0 +1,28 @@ +package com.baeldung.axon.gui; + +import java.util.UUID; + +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.axon.coreapi.commands.CreateMessageCommand; +import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; + +@RestController +public class MessagesRestEndpoint { + + private final CommandGateway commandGateway; + + public MessagesRestEndpoint(CommandGateway commandGateway) { + this.commandGateway = commandGateway; + } + + @PostMapping("/hello") + public void publishMessages() { + final String itemId = UUID.randomUUID().toString(); + commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); + commandGateway.send(new MarkReadMessageCommand(itemId)); + } + +} From d8ef050867fbf473260f51509ed775a719737879 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:16:31 +0100 Subject: [PATCH 014/139] BAEL-2435 Add JPA and H2 dependencies Add JPA and H2 dependencies to allow event sourcing, as for event sourcing and EventStore is mandatory, and to make an EventStore a database needs to be present for Axon's auto-configuration --- axon/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/axon/pom.xml b/axon/pom.xml index 639c50d70b..03d2499a99 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -44,6 +44,17 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + From 557ce655522559c849e4a02cdd54955872d700c5 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Tue, 18 Dec 2018 15:17:16 +0100 Subject: [PATCH 015/139] BAEL-2435 Update main application Update the MessagesRunner to be a spring boot application --- .../com/baeldung/axon/MessagesRunner.java | 51 ++----------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java index 77b50d09bd..4f83dd86f0 100644 --- a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java +++ b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java @@ -1,54 +1,13 @@ package com.baeldung.axon; -import com.baeldung.axon.aggregates.MessagesAggregate; -import com.baeldung.axon.commands.CreateMessageCommand; -import com.baeldung.axon.commands.MarkReadMessageCommand; -import com.baeldung.axon.eventhandlers.MessagesEventHandler; -import org.axonframework.commandhandling.AggregateAnnotationCommandHandler; -import org.axonframework.commandhandling.CommandBus; -import org.axonframework.commandhandling.SimpleCommandBus; -import org.axonframework.commandhandling.gateway.CommandGateway; -import org.axonframework.commandhandling.gateway.DefaultCommandGateway; -import org.axonframework.eventhandling.AnnotationEventListenerAdapter; -import org.axonframework.eventsourcing.EventSourcingRepository; -import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore; -import org.axonframework.eventsourcing.eventstore.EventStore; -import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine; - -import java.util.UUID; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +@SpringBootApplication public class MessagesRunner { public static void main(String[] args) { - CommandBus commandBus = new SimpleCommandBus(); - - CommandGateway commandGateway = new DefaultCommandGateway(commandBus); - - EventStore eventStore = new EmbeddedEventStore(new InMemoryEventStorageEngine()); - - EventSourcingRepository repository = - new EventSourcingRepository<>(MessagesAggregate.class, eventStore); - - - AggregateAnnotationCommandHandler messagesAggregateAggregateAnnotationCommandHandler = - new AggregateAnnotationCommandHandler(MessagesAggregate.class, repository); - messagesAggregateAggregateAnnotationCommandHandler.subscribe(commandBus); - - final AnnotationEventListenerAdapter annotationEventListenerAdapter = - new AnnotationEventListenerAdapter(new MessagesEventHandler()); - eventStore.subscribe(eventMessages -> eventMessages.forEach(e -> { - try { - annotationEventListenerAdapter.handle(e); - } catch (Exception e1) { - throw new RuntimeException(e1); - - } - } - - )); - - final String itemId = UUID.randomUUID().toString(); - commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); - commandGateway.send(new MarkReadMessageCommand(itemId)); + SpringApplication.run(MessagesRunner.class, args); } + } \ No newline at end of file From 64b205a6ce2360de18c418fef3da2e53f1468e90 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Fri, 21 Dec 2018 12:19:09 +0400 Subject: [PATCH 016/139] Vector iterator --- .../src/main/java/com/baeldung/java/list/VectorExample.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java b/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java index 38736390ca..7debc07911 100644 --- a/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java +++ b/core-java-collections/src/main/java/com/baeldung/java/list/VectorExample.java @@ -1,6 +1,7 @@ package com.baeldung.java.list; import java.util.Enumeration; +import java.util.Iterator; import java.util.Vector; public class VectorExample { @@ -16,6 +17,11 @@ public class VectorExample { while(e.hasMoreElements()){ System.out.println(e.nextElement()); } + + Iterator iterator = vector.iterator(); + while (iterator.hasNext()) { + System.out.println(iterator.next()); + } } } From c2fc5c0aa676e86696bf2ae9435e343803520077 Mon Sep 17 00:00:00 2001 From: Karanbir Singh Date: Sat, 22 Dec 2018 19:27:25 +0530 Subject: [PATCH 017/139] spelling mistake - minor one --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3fe5e3bf0..378d77196a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Java and Spring Tutorials ================ This project is **a collection of small and focused tutorials** - each covering a single and well defined area of development in the Java ecosystem. -A strong focus of these is, of course, the Spring Framework - Spring, Spring Boot and Spring Securiyt. +A strong focus of these is, of course, the Spring Framework - Spring, Spring Boot and Spring Security. In additional to Spring, the following technologies are in focus: `core Java`, `Jackson`, `HttpClient`, `Guava`. From 2279246a426c9d35618ce2a1dc2f26b724922060 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:39:40 +0100 Subject: [PATCH 018/139] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. First, update the commands and events, adding an extra command/event to flesh out the domain some what --- .../coreapi/commands/ConfirmOrderCommand.java | 36 ++++++++++++++++ .../commands/CreateMessageCommand.java | 42 ------------------ .../commands/MarkReadMessageCommand.java | 36 ---------------- .../coreapi/commands/PlaceOrderCommand.java | 43 +++++++++++++++++++ .../coreapi/commands/ShipOrderCommand.java | 36 ++++++++++++++++ .../coreapi/events/MessageCreatedEvent.java | 39 ----------------- .../axon/coreapi/events/MessageReadEvent.java | 33 -------------- .../coreapi/events/OrderConfirmedEvent.java | 33 ++++++++++++++ .../axon/coreapi/events/OrderPlacedEvent.java | 40 +++++++++++++++++ .../coreapi/events/OrderShippedEvent.java | 33 ++++++++++++++ 10 files changed, 221 insertions(+), 150 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java delete mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java new file mode 100644 index 0000000000..ba04343af1 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -0,0 +1,36 @@ +package com.baeldung.axon.coreapi.commands; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +import java.util.Objects; + +public class ConfirmOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + + public ConfirmOrderCommand(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ConfirmOrderCommand other = (ConfirmOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java deleted file mode 100644 index fd03d6b269..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/CreateMessageCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.baeldung.axon.coreapi.commands; - -import java.util.Objects; - -import org.axonframework.modelling.command.TargetAggregateIdentifier; - -public class CreateMessageCommand { - - @TargetAggregateIdentifier - private final String id; - private final String text; - - public CreateMessageCommand(String id, String text) { - this.id = id; - this.text = text; - } - - public String getId() { - return id; - } - - public String getText() { - return text; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CreateMessageCommand that = (CreateMessageCommand) o; - return Objects.equals(id, that.id) && Objects.equals(text, that.text); - } - - @Override - public int hashCode() { - return Objects.hash(id, text); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java deleted file mode 100644 index ec68a380f8..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/MarkReadMessageCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.axon.coreapi.commands; - -import java.util.Objects; - -import org.axonframework.modelling.command.TargetAggregateIdentifier; - -public class MarkReadMessageCommand { - - @TargetAggregateIdentifier - private final String id; - - public MarkReadMessageCommand(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MarkReadMessageCommand that = (MarkReadMessageCommand) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java new file mode 100644 index 0000000000..cde2d7f1ae --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java @@ -0,0 +1,43 @@ +package com.baeldung.axon.coreapi.commands; + +import java.util.Objects; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +public class PlaceOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + private final String product; + + public PlaceOrderCommand(String orderId, String product) { + this.orderId = orderId; + this.product = product; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final PlaceOrderCommand other = (PlaceOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java new file mode 100644 index 0000000000..75469533b9 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -0,0 +1,36 @@ +package com.baeldung.axon.coreapi.commands; + +import java.util.Objects; + +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +public class ShipOrderCommand { + + @TargetAggregateIdentifier + private final String orderId; + + public ShipOrderCommand(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ShipOrderCommand other = (ShipOrderCommand) obj; + return Objects.equals(this.orderId, other.orderId); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java deleted file mode 100644 index debf383771..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageCreatedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.baeldung.axon.coreapi.events; - -import java.util.Objects; - -public class MessageCreatedEvent { - - private final String id; - private final String text; - - public MessageCreatedEvent(String id, String text) { - this.id = id; - this.text = text; - } - - public String getId() { - return id; - } - - public String getText() { - return text; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MessageCreatedEvent that = (MessageCreatedEvent) o; - return Objects.equals(id, that.id) && Objects.equals(text, that.text); - } - - @Override - public int hashCode() { - return Objects.hash(id, text); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java deleted file mode 100644 index f90bfb054e..0000000000 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/MessageReadEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.axon.coreapi.events; - -import java.util.Objects; - -public class MessageReadEvent { - - private final String id; - - public MessageReadEvent(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MessageReadEvent that = (MessageReadEvent) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java new file mode 100644 index 0000000000..1706b08023 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -0,0 +1,33 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderConfirmedEvent { + + private final String orderId; + + public OrderConfirmedEvent(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderConfirmedEvent other = (OrderConfirmedEvent) obj; + return Objects.equals(this.orderId, other.orderId); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java new file mode 100644 index 0000000000..8d5364f4c6 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java @@ -0,0 +1,40 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderPlacedEvent { + + private final String orderId; + private final String product; + + public OrderPlacedEvent(String orderId, String product) { + this.orderId = orderId; + this.product = product; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderPlacedEvent other = (OrderPlacedEvent) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java new file mode 100644 index 0000000000..5abcd09a3c --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -0,0 +1,33 @@ +package com.baeldung.axon.coreapi.events; + +import java.util.Objects; + +public class OrderShippedEvent { + + private final String orderId; + + public OrderShippedEvent(String orderId) { + this.orderId = orderId; + } + + public String getOrderId() { + return orderId; + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderShippedEvent other = (OrderShippedEvent) obj; + return Objects.equals(this.orderId, other.orderId); + } +} \ No newline at end of file From 5dd6d520254050e3378cbc06c46f1985467a8557 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 27 Dec 2018 12:48:51 +0400 Subject: [PATCH 019/139] Vector class more tests --- .../com/baeldung/performance/ArrayListBenchmark.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java index 5c3f7531e3..1eeb17df87 100644 --- a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java +++ b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java @@ -49,6 +49,11 @@ public class ArrayListBenchmark { return state.employeeList.contains(state.employee); } + @Benchmark + public boolean testContainsVector(ArrayListBenchmark.MyState state) { + return state.employeeVector.contains(state.employee); + } + @Benchmark public int testIndexOf(ArrayListBenchmark.MyState state) { return state.employeeList.indexOf(state.employee); @@ -73,6 +78,11 @@ public class ArrayListBenchmark { state.employeeList.add(new Employee(state.iterations + 1, "John")); } + @Benchmark + public void testAddVector(ArrayListBenchmark.MyState state) { + state.employeeVector.add(new Employee(state.iterations + 1, "John")); + } + public static void main(String[] args) throws Exception { Options options = new OptionsBuilder() .include(ArrayListBenchmark.class.getSimpleName()).threads(1) From bd0a1efe707ba65b04f21a21f621110b7769ab0a Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:51:08 +0100 Subject: [PATCH 020/139] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. To that end the MessagesAggregate should be replaced by an OrderAggregate. Additionally, add some decision making logic which denies the shipping of an order if it hasn't been confirmed yet. Adjust and update thee unit test accordingly --- .../axon/commandmodel/MessagesAggregate.java | 38 ------------ .../axon/commandmodel/OrderAggregate.java | 58 +++++++++++++++++++ .../MessagesAggregateUnitTest.java | 40 ------------- .../commandmodel/OrderAggregateUnitTest.java | 48 +++++++++++++++ 4 files changed, 106 insertions(+), 78 deletions(-) delete mode 100644 axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java create mode 100644 axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java delete mode 100644 axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java create mode 100644 axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java deleted file mode 100644 index 1ab9501617..0000000000 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/MessagesAggregate.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.baeldung.axon.commandmodel; - -import static org.axonframework.modelling.command.AggregateLifecycle.apply; - -import org.axonframework.commandhandling.CommandHandler; -import org.axonframework.eventsourcing.EventSourcingHandler; -import org.axonframework.modelling.command.AggregateIdentifier; -import org.axonframework.spring.stereotype.Aggregate; - -import com.baeldung.axon.coreapi.commands.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -@Aggregate -public class MessagesAggregate { - - @AggregateIdentifier - private String id; - - public MessagesAggregate() { - } - - @CommandHandler - public MessagesAggregate(CreateMessageCommand command) { - apply(new MessageCreatedEvent(command.getId(), command.getText())); - } - - @CommandHandler - public void handle(MarkReadMessageCommand command) { - apply(new MessageReadEvent(id)); - } - - @EventSourcingHandler - public void on(MessageCreatedEvent event) { - this.id = event.getId(); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java new file mode 100644 index 0000000000..fd4f901032 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java @@ -0,0 +1,58 @@ +package com.baeldung.axon.commandmodel; + +import static org.axonframework.modelling.command.AggregateLifecycle.apply; + +import org.axonframework.commandhandling.CommandHandler; +import org.axonframework.eventsourcing.EventSourcingHandler; +import org.axonframework.modelling.command.AggregateIdentifier; +import org.axonframework.spring.stereotype.Aggregate; + +import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand; +import com.baeldung.axon.coreapi.commands.PlaceOrderCommand; +import com.baeldung.axon.coreapi.commands.ShipOrderCommand; +import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; +import com.baeldung.axon.coreapi.events.OrderPlacedEvent; +import com.baeldung.axon.coreapi.events.OrderShippedEvent; + +@Aggregate +public class OrderAggregate { + + @AggregateIdentifier + private String orderId; + private boolean orderConfirmed; + + @CommandHandler + public OrderAggregate(PlaceOrderCommand command) { + apply(new OrderPlacedEvent(command.getOrderId(), command.getProduct())); + } + + @CommandHandler + public void handle(ConfirmOrderCommand command) { + apply(new OrderConfirmedEvent(orderId)); + } + + @CommandHandler + public void handle(ShipOrderCommand command) { + if (!orderConfirmed) { + throw new IllegalStateException("Cannot ship an order which has not ben confirmed yet."); + } + + apply(new OrderShippedEvent(orderId)); + } + + @EventSourcingHandler + public void on(OrderPlacedEvent event) { + this.orderId = event.getOrderId(); + orderConfirmed = false; + } + + @EventSourcingHandler + public void on(OrderConfirmedEvent event) { + orderConfirmed = true; + } + + protected OrderAggregate() { + // Required by Axon to build a default Aggregate prior to Event Sourcing + } + +} \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java deleted file mode 100644 index 46357ddff8..0000000000 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/MessagesAggregateUnitTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.baeldung.axon.commandmodel; - -import java.util.UUID; - -import org.axonframework.test.aggregate.AggregateTestFixture; -import org.axonframework.test.aggregate.FixtureConfiguration; -import org.junit.*; - -import com.baeldung.axon.coreapi.commands.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -public class MessagesAggregateUnitTest { - - private FixtureConfiguration fixture; - - @Before - public void setUp() { - fixture = new AggregateTestFixture<>(MessagesAggregate.class); - } - - @Test - public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() { - String eventText = "Hello, how is your day?"; - String id = UUID.randomUUID().toString(); - fixture.given() - .when(new CreateMessageCommand(id, eventText)) - .expectEvents(new MessageCreatedEvent(id, eventText)); - } - - @Test - public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() { - String id = UUID.randomUUID().toString(); - - fixture.given(new MessageCreatedEvent(id, "Hello :-)")) - .when(new MarkReadMessageCommand(id)) - .expectEvents(new MessageReadEvent(id)); - } -} \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java new file mode 100644 index 0000000000..e7dfdeb794 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.axon.commandmodel; + +import java.util.UUID; + +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.*; + +import com.baeldung.axon.coreapi.commands.PlaceOrderCommand; +import com.baeldung.axon.coreapi.commands.ShipOrderCommand; +import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; +import com.baeldung.axon.coreapi.events.OrderPlacedEvent; +import com.baeldung.axon.coreapi.events.OrderShippedEvent; + +public class OrderAggregateUnitTest { + + private static final String ORDER_ID = UUID.randomUUID().toString(); + private static final String DEFAULT_PRODUCT = "Deluxe Chair"; + + private FixtureConfiguration fixture; + + @Before + public void setUp() { + fixture = new AggregateTestFixture<>(OrderAggregate.class); + } + + @Test + public void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() { + fixture.givenNoPriorActivity() + .when(new PlaceOrderCommand(ORDER_ID, DEFAULT_PRODUCT)) + .expectEvents(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)); + } + + @Test + public void givenOrderPlacedEvent_whenShipOrderCommand_thenShouldThrowIllegalStateException() { + fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)) + .when(new ShipOrderCommand(ORDER_ID)) + .expectException(IllegalStateException.class); + } + + @Test + public void givenOrderPlacedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() { + fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT), new OrderConfirmedEvent(ORDER_ID)) + .when(new ShipOrderCommand(ORDER_ID)) + .expectEvents(new OrderShippedEvent(ORDER_ID)); + } + +} \ No newline at end of file From eab6dfe0dd5e29afd990f7b3770242c93d1f3d01 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 09:55:49 +0100 Subject: [PATCH 021/139] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. Update the endpoint to reflect the order focus i.o. the message focus. Additionally, add a POST endpoint which would return an exception due to the state check in the aggregate --- .../axon/gui/MessagesRestEndpoint.java | 28 ------------- .../baeldung/axon/gui/OrderRestEndpoint.java | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 28 deletions(-) delete mode 100644 axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java create mode 100644 axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java diff --git a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java deleted file mode 100644 index ddbc3e2fc5..0000000000 --- a/axon/src/main/java/com/baeldung/axon/gui/MessagesRestEndpoint.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.axon.gui; - -import java.util.UUID; - -import org.axonframework.commandhandling.gateway.CommandGateway; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.axon.coreapi.commands.CreateMessageCommand; -import com.baeldung.axon.coreapi.commands.MarkReadMessageCommand; - -@RestController -public class MessagesRestEndpoint { - - private final CommandGateway commandGateway; - - public MessagesRestEndpoint(CommandGateway commandGateway) { - this.commandGateway = commandGateway; - } - - @PostMapping("/hello") - public void publishMessages() { - final String itemId = UUID.randomUUID().toString(); - commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); - commandGateway.send(new MarkReadMessageCommand(itemId)); - } - -} diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java new file mode 100644 index 0000000000..3c86f9c3b1 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -0,0 +1,40 @@ +package com.baeldung.axon.gui; + +import java.util.UUID; + +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand; +import com.baeldung.axon.coreapi.commands.PlaceOrderCommand; +import com.baeldung.axon.coreapi.commands.ShipOrderCommand; + +@RestController +public class OrderRestEndpoint { + + private static final String DEFAULT_PRODUCT = "Deluxe Chair"; + + private final CommandGateway commandGateway; + + public OrderRestEndpoint(CommandGateway commandGateway) { + this.commandGateway = commandGateway; + } + + @PostMapping("/ship-order") + public void shipOrder() { + String orderId = UUID.randomUUID().toString(); + commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + commandGateway.send(new ConfirmOrderCommand(orderId)); + commandGateway.send(new ShipOrderCommand(orderId)); + } + + @PostMapping("/ship-unconfirmed-order") + public void shipUnconfirmedOrder() { + String orderId = UUID.randomUUID().toString(); + commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + // This throws an exception, as an Order cannot be shipped if it has not been confirmed yet. + commandGateway.send(new ShipOrderCommand(orderId)); + } + +} From 84b6dc1dbb7badacaed4bbcc5a889ba5a1d5171c Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:36:10 +0100 Subject: [PATCH 022/139] BAEL-2435 Switch domain around Change the domain from 'Messages' to 'Order' as that domain is better suited for an example project like this. The Query Model would be better suited to revolve around the OrderedProducts rather than just printing out a line of text. To that end, add a OrderedProduct model with the OrderStatus, which is updated in the (renamed) OrderedProductsEventHandler upon all the events --- .../axon/coreapi/queries/OrderStatus.java | 7 +++ .../axon/coreapi/queries/OrderedProduct.java | 55 +++++++++++++++++++ .../axon/querymodel/MessagesEventHandler.java | 21 ------- .../OrderedProductsEventHandler.java | 42 ++++++++++++++ 4 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java delete mode 100644 axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java create mode 100644 axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java new file mode 100644 index 0000000000..d215c5fc32 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderStatus.java @@ -0,0 +1,7 @@ +package com.baeldung.axon.coreapi.queries; + +public enum OrderStatus { + + PLACED, CONFIRMED, SHIPPED + +} diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java new file mode 100644 index 0000000000..25096eeb42 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java @@ -0,0 +1,55 @@ +package com.baeldung.axon.coreapi.queries; + +import java.util.Objects; + +public class OrderedProduct { + + private final String orderId; + private final String product; + private OrderStatus orderStatus; + + public OrderedProduct(String orderId, String product) { + this.orderId = orderId; + this.product = product; + orderStatus = OrderStatus.PLACED; + } + + public String getOrderId() { + return orderId; + } + + public String getProduct() { + return product; + } + + public OrderStatus getOrderStatus() { + return orderStatus; + } + + public void setOrderConfirmed() { + this.orderStatus = OrderStatus.CONFIRMED; + } + + public void setOrderShipped() { + this.orderStatus = OrderStatus.SHIPPED; + } + + @Override + public int hashCode() { + return Objects.hash(orderId, product, orderStatus); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final OrderedProduct other = (OrderedProduct) obj; + return Objects.equals(this.orderId, other.orderId) + && Objects.equals(this.product, other.product) + && Objects.equals(this.orderStatus, other.orderStatus); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java deleted file mode 100644 index 6988d40a53..0000000000 --- a/axon/src/main/java/com/baeldung/axon/querymodel/MessagesEventHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.baeldung.axon.querymodel; - -import org.axonframework.eventhandling.EventHandler; -import org.springframework.stereotype.Service; - -import com.baeldung.axon.coreapi.events.MessageCreatedEvent; -import com.baeldung.axon.coreapi.events.MessageReadEvent; - -@Service -public class MessagesEventHandler { - - @EventHandler - public void handle(MessageCreatedEvent event) { - System.out.println("Message received: " + event.getText() + " (" + event.getId() + ")"); - } - - @EventHandler - public void handle(MessageReadEvent event) { - System.out.println("Message read: " + event.getId()); - } -} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java new file mode 100644 index 0000000000..7bcdb27af7 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -0,0 +1,42 @@ +package com.baeldung.axon.querymodel; + +import java.util.HashMap; +import java.util.Map; + +import org.axonframework.eventhandling.EventHandler; +import org.springframework.stereotype.Service; + +import com.baeldung.axon.coreapi.queries.OrderedProduct; +import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; +import com.baeldung.axon.coreapi.events.OrderPlacedEvent; +import com.baeldung.axon.coreapi.events.OrderShippedEvent; + +@Service +public class OrderedProductsEventHandler { + + private final Map orderedProducts = new HashMap<>(); + + @EventHandler + public void on(OrderPlacedEvent event) { + String orderId = event.getOrderId(); + orderedProducts.put(orderId, new OrderedProduct(orderId, event.getProduct())); + + } + + @EventHandler + public void on(OrderShippedEvent event) { + orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { + orderedProduct.setOrderShipped(); + return orderedProduct; + }); + } + + @EventHandler + public void on(OrderConfirmedEvent event) { + orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { + orderedProduct.setOrderConfirmed(); + return orderedProduct; + }); + } + +} \ No newline at end of file From 769af6759ed6dca02d6c8732f2627e11e5f66a48 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:39:42 +0100 Subject: [PATCH 023/139] BAEL-2435 Introduce Query message logic Introduce a FindAllOrderedProductsQuery query message, which is published on the QueryGateway through the OrderRestEndpoint and handled by the OrderedProductsEventHandler --- .../queries/FindAllOrderedProductsQuery.java | 5 +++++ .../com/baeldung/axon/gui/OrderRestEndpoint.java | 16 +++++++++++++++- .../querymodel/OrderedProductsEventHandler.java | 11 ++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java new file mode 100644 index 0000000000..9d6ca2cfb2 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/FindAllOrderedProductsQuery.java @@ -0,0 +1,5 @@ +package com.baeldung.axon.coreapi.queries; + +public class FindAllOrderedProductsQuery { + +} diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java index 3c86f9c3b1..3b8be0bc46 100644 --- a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -1,14 +1,20 @@ package com.baeldung.axon.gui; +import java.util.List; import java.util.UUID; import org.axonframework.commandhandling.gateway.CommandGateway; +import org.axonframework.messaging.responsetypes.ResponseTypes; +import org.axonframework.queryhandling.QueryGateway; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand; import com.baeldung.axon.coreapi.commands.PlaceOrderCommand; import com.baeldung.axon.coreapi.commands.ShipOrderCommand; +import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery; +import com.baeldung.axon.coreapi.queries.OrderedProduct; @RestController public class OrderRestEndpoint { @@ -16,9 +22,11 @@ public class OrderRestEndpoint { private static final String DEFAULT_PRODUCT = "Deluxe Chair"; private final CommandGateway commandGateway; + private final QueryGateway queryGateway; - public OrderRestEndpoint(CommandGateway commandGateway) { + public OrderRestEndpoint(CommandGateway commandGateway, QueryGateway queryGateway) { this.commandGateway = commandGateway; + this.queryGateway = queryGateway; } @PostMapping("/ship-order") @@ -37,4 +45,10 @@ public class OrderRestEndpoint { commandGateway.send(new ShipOrderCommand(orderId)); } + @GetMapping("/all-orders") + public List findAllOrderedProducts() { + return queryGateway.query(new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(OrderedProduct.class)) + .join(); + } + } diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java index 7bcdb27af7..c2bf48614b 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -1,15 +1,19 @@ package com.baeldung.axon.querymodel; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.axonframework.eventhandling.EventHandler; +import org.axonframework.queryhandling.QueryHandler; import org.springframework.stereotype.Service; -import com.baeldung.axon.coreapi.queries.OrderedProduct; import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; import com.baeldung.axon.coreapi.events.OrderPlacedEvent; import com.baeldung.axon.coreapi.events.OrderShippedEvent; +import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery; +import com.baeldung.axon.coreapi.queries.OrderedProduct; @Service public class OrderedProductsEventHandler { @@ -39,4 +43,9 @@ public class OrderedProductsEventHandler { }); } + @QueryHandler + public List handle(FindAllOrderedProductsQuery query) { + return new ArrayList<>(orderedProducts.values()); + } + } \ No newline at end of file From 4c7303c2936706da2aa207eae4b41f0caf8f9d19 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:46:45 +0100 Subject: [PATCH 024/139] BAEL-2435 Rename main file Rename main file from MessagesRunner to OrderApplication --- .../axon/{MessagesRunner.java => OrderApplication.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename axon/src/main/java/com/baeldung/axon/{MessagesRunner.java => OrderApplication.java} (70%) diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/OrderApplication.java similarity index 70% rename from axon/src/main/java/com/baeldung/axon/MessagesRunner.java rename to axon/src/main/java/com/baeldung/axon/OrderApplication.java index 4f83dd86f0..8f507e141c 100644 --- a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java +++ b/axon/src/main/java/com/baeldung/axon/OrderApplication.java @@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class MessagesRunner { +public class OrderApplication { public static void main(String[] args) { - SpringApplication.run(MessagesRunner.class, args); + SpringApplication.run(OrderApplication.class, args); } } \ No newline at end of file From d5ad67a801d96ba707729c0dcb87e331eef5ae28 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Thu, 27 Dec 2018 10:47:22 +0100 Subject: [PATCH 025/139] BAEL-2435 Add http resource Add http resource to try out all the end points when running the application in Intellij --- axon/src/main/resources/order-api.http | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 axon/src/main/resources/order-api.http diff --git a/axon/src/main/resources/order-api.http b/axon/src/main/resources/order-api.http new file mode 100644 index 0000000000..a3c69c72bc --- /dev/null +++ b/axon/src/main/resources/order-api.http @@ -0,0 +1,11 @@ +POST http://localhost:8080/ship-order + +### + +POST http://localhost:8080/ship-unconfirmed-order + +### + +GET http://localhost:8080/all-orders + +### From 8ce227cce7d92ca7ac1e5e7b0e63b8b41da604a2 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Fri, 28 Dec 2018 16:26:57 +0400 Subject: [PATCH 026/139] immutable sets --- .../com/baeldung/set/UnmodifiableSet.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java diff --git a/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java b/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java new file mode 100644 index 0000000000..d821c46a3c --- /dev/null +++ b/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java @@ -0,0 +1,44 @@ +package com.baeldung.set; + +import com.google.common.collect.ImmutableSet; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class UnmodifiableSet { + + public static void main(String[] args) { + + Set set = new HashSet<>(); + set.add("Canada"); + set.add("USA"); + + coreJDK(set); + guavaOf(); + copyOf(set); + setOf(); + } + + private static void setOf() { + Set immutable = Set.of("Canada", "USA"); + System.out.println(immutable); + } + + private static void guavaOf() { + Set immutable = ImmutableSet.of("Canada", "USA"); + System.out.println(immutable); + } + + private static void copyOf(Set set) { + Set immutable = ImmutableSet.copyOf(set); + set.add("Costa Rica"); + System.out.println(immutable); + } + + private static void coreJDK(Set set) { + Set unmodifiableSet = Collections.unmodifiableSet(set); + set.add("Costa Rica"); + System.out.println(unmodifiableSet); + } +} From fb8183d69434b3f3a4b3d2ec311cdbe6a40d98da Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Fri, 28 Dec 2018 16:33:41 +0400 Subject: [PATCH 027/139] comment java 9 --- .../src/main/java/com/baeldung/set/UnmodifiableSet.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java b/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java index d821c46a3c..06f477c50a 100644 --- a/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java +++ b/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java @@ -17,12 +17,12 @@ public class UnmodifiableSet { coreJDK(set); guavaOf(); copyOf(set); - setOf(); + java9Of(); } - private static void setOf() { - Set immutable = Set.of("Canada", "USA"); - System.out.println(immutable); + private static void java9Of() { + //Set immutable = Set.of("Canada", "USA"); + //System.out.println(immutable); } private static void guavaOf() { From 03306112bdc117277afa828912a81b5fe938d158 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Fri, 28 Dec 2018 15:58:41 +0100 Subject: [PATCH 028/139] BAEL-2435 Minor clean ups -Add toString() function to messages/query-model -Fix typo in exception -Reorder event handlers in OrderedProductsEventHandler -Replace usage of constants for local fields -Add missing Aggregate test case --- .../axon/commandmodel/OrderAggregate.java | 2 +- .../coreapi/commands/ConfirmOrderCommand.java | 7 ++++ .../coreapi/commands/PlaceOrderCommand.java | 8 +++++ .../coreapi/commands/ShipOrderCommand.java | 7 ++++ .../coreapi/events/OrderConfirmedEvent.java | 7 ++++ .../axon/coreapi/events/OrderPlacedEvent.java | 8 +++++ .../coreapi/events/OrderShippedEvent.java | 7 ++++ .../axon/coreapi/queries/OrderedProduct.java | 9 +++++ .../baeldung/axon/gui/OrderRestEndpoint.java | 8 ++--- .../OrderedProductsEventHandler.java | 17 +++++----- .../commandmodel/OrderAggregateUnitTest.java | 33 +++++++++++++------ 11 files changed, 88 insertions(+), 25 deletions(-) diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java index fd4f901032..b37b2fdd66 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/OrderAggregate.java @@ -34,7 +34,7 @@ public class OrderAggregate { @CommandHandler public void handle(ShipOrderCommand command) { if (!orderConfirmed) { - throw new IllegalStateException("Cannot ship an order which has not ben confirmed yet."); + throw new IllegalStateException("Cannot ship an order which has not been confirmed yet."); } apply(new OrderShippedEvent(orderId)); diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java index ba04343af1..244b69f3b7 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ConfirmOrderCommand.java @@ -33,4 +33,11 @@ public class ConfirmOrderCommand { final ConfirmOrderCommand other = (ConfirmOrderCommand) obj; return Objects.equals(this.orderId, other.orderId); } + + @Override + public String toString() { + return "ConfirmOrderCommand{" + + "orderId='" + orderId + '\'' + + '}'; + } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java index cde2d7f1ae..c70d503050 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/PlaceOrderCommand.java @@ -40,4 +40,12 @@ public class PlaceOrderCommand { return Objects.equals(this.orderId, other.orderId) && Objects.equals(this.product, other.product); } + + @Override + public String toString() { + return "PlaceOrderCommand{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + '}'; + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java index 75469533b9..7312bc1fdb 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/commands/ShipOrderCommand.java @@ -33,4 +33,11 @@ public class ShipOrderCommand { final ShipOrderCommand other = (ShipOrderCommand) obj; return Objects.equals(this.orderId, other.orderId); } + + @Override + public String toString() { + return "ShipOrderCommand{" + + "orderId='" + orderId + '\'' + + '}'; + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java index 1706b08023..d2b7d58435 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderConfirmedEvent.java @@ -30,4 +30,11 @@ public class OrderConfirmedEvent { final OrderConfirmedEvent other = (OrderConfirmedEvent) obj; return Objects.equals(this.orderId, other.orderId); } + + @Override + public String toString() { + return "OrderConfirmedEvent{" + + "orderId='" + orderId + '\'' + + '}'; + } } diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java index 8d5364f4c6..06de4c5f9f 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderPlacedEvent.java @@ -37,4 +37,12 @@ public class OrderPlacedEvent { return Objects.equals(this.orderId, other.orderId) && Objects.equals(this.product, other.product); } + + @Override + public String toString() { + return "OrderPlacedEvent{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + '}'; + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java index 5abcd09a3c..76aa684629 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/events/OrderShippedEvent.java @@ -30,4 +30,11 @@ public class OrderShippedEvent { final OrderShippedEvent other = (OrderShippedEvent) obj; return Objects.equals(this.orderId, other.orderId); } + + @Override + public String toString() { + return "OrderShippedEvent{" + + "orderId='" + orderId + '\'' + + '}'; + } } \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java index 25096eeb42..d847bb2a98 100644 --- a/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java +++ b/axon/src/main/java/com/baeldung/axon/coreapi/queries/OrderedProduct.java @@ -52,4 +52,13 @@ public class OrderedProduct { && Objects.equals(this.product, other.product) && Objects.equals(this.orderStatus, other.orderStatus); } + + @Override + public String toString() { + return "OrderedProduct{" + + "orderId='" + orderId + '\'' + + ", product='" + product + '\'' + + ", orderStatus=" + orderStatus + + '}'; + } } diff --git a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java index 3b8be0bc46..a9f34cc691 100644 --- a/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java +++ b/axon/src/main/java/com/baeldung/axon/gui/OrderRestEndpoint.java @@ -19,8 +19,6 @@ import com.baeldung.axon.coreapi.queries.OrderedProduct; @RestController public class OrderRestEndpoint { - private static final String DEFAULT_PRODUCT = "Deluxe Chair"; - private final CommandGateway commandGateway; private final QueryGateway queryGateway; @@ -32,7 +30,7 @@ public class OrderRestEndpoint { @PostMapping("/ship-order") public void shipOrder() { String orderId = UUID.randomUUID().toString(); - commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + commandGateway.send(new PlaceOrderCommand(orderId, "Deluxe Chair")); commandGateway.send(new ConfirmOrderCommand(orderId)); commandGateway.send(new ShipOrderCommand(orderId)); } @@ -40,7 +38,7 @@ public class OrderRestEndpoint { @PostMapping("/ship-unconfirmed-order") public void shipUnconfirmedOrder() { String orderId = UUID.randomUUID().toString(); - commandGateway.send(new PlaceOrderCommand(orderId, DEFAULT_PRODUCT)); + commandGateway.send(new PlaceOrderCommand(orderId, "Deluxe Chair")); // This throws an exception, as an Order cannot be shipped if it has not been confirmed yet. commandGateway.send(new ShipOrderCommand(orderId)); } @@ -48,7 +46,7 @@ public class OrderRestEndpoint { @GetMapping("/all-orders") public List findAllOrderedProducts() { return queryGateway.query(new FindAllOrderedProductsQuery(), ResponseTypes.multipleInstancesOf(OrderedProduct.class)) - .join(); + .join(); } } diff --git a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java index c2bf48614b..d4cf3d999b 100644 --- a/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java +++ b/axon/src/main/java/com/baeldung/axon/querymodel/OrderedProductsEventHandler.java @@ -24,15 +24,6 @@ public class OrderedProductsEventHandler { public void on(OrderPlacedEvent event) { String orderId = event.getOrderId(); orderedProducts.put(orderId, new OrderedProduct(orderId, event.getProduct())); - - } - - @EventHandler - public void on(OrderShippedEvent event) { - orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { - orderedProduct.setOrderShipped(); - return orderedProduct; - }); } @EventHandler @@ -43,6 +34,14 @@ public class OrderedProductsEventHandler { }); } + @EventHandler + public void on(OrderShippedEvent event) { + orderedProducts.computeIfPresent(event.getOrderId(), (orderId, orderedProduct) -> { + orderedProduct.setOrderShipped(); + return orderedProduct; + }); + } + @QueryHandler public List handle(FindAllOrderedProductsQuery query) { return new ArrayList<>(orderedProducts.values()); diff --git a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java index e7dfdeb794..9beedbaa19 100644 --- a/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java +++ b/axon/src/test/java/com/baeldung/axon/commandmodel/OrderAggregateUnitTest.java @@ -6,6 +6,7 @@ import org.axonframework.test.aggregate.AggregateTestFixture; import org.axonframework.test.aggregate.FixtureConfiguration; import org.junit.*; +import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand; import com.baeldung.axon.coreapi.commands.PlaceOrderCommand; import com.baeldung.axon.coreapi.commands.ShipOrderCommand; import com.baeldung.axon.coreapi.events.OrderConfirmedEvent; @@ -14,9 +15,6 @@ import com.baeldung.axon.coreapi.events.OrderShippedEvent; public class OrderAggregateUnitTest { - private static final String ORDER_ID = UUID.randomUUID().toString(); - private static final String DEFAULT_PRODUCT = "Deluxe Chair"; - private FixtureConfiguration fixture; @Before @@ -26,23 +24,38 @@ public class OrderAggregateUnitTest { @Test public void giveNoPriorActivity_whenPlaceOrderCommand_thenShouldPublishOrderPlacedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; fixture.givenNoPriorActivity() - .when(new PlaceOrderCommand(ORDER_ID, DEFAULT_PRODUCT)) - .expectEvents(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)); + .when(new PlaceOrderCommand(orderId, product)) + .expectEvents(new OrderPlacedEvent(orderId, product)); + } + + @Test + public void givenOrderPlacedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() { + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product)) + .when(new ConfirmOrderCommand(orderId)) + .expectEvents(new OrderConfirmedEvent(orderId)); } @Test public void givenOrderPlacedEvent_whenShipOrderCommand_thenShouldThrowIllegalStateException() { - fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT)) - .when(new ShipOrderCommand(ORDER_ID)) + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product)) + .when(new ShipOrderCommand(orderId)) .expectException(IllegalStateException.class); } @Test public void givenOrderPlacedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() { - fixture.given(new OrderPlacedEvent(ORDER_ID, DEFAULT_PRODUCT), new OrderConfirmedEvent(ORDER_ID)) - .when(new ShipOrderCommand(ORDER_ID)) - .expectEvents(new OrderShippedEvent(ORDER_ID)); + String orderId = UUID.randomUUID().toString(); + String product = "Deluxe Chair"; + fixture.given(new OrderPlacedEvent(orderId, product), new OrderConfirmedEvent(orderId)) + .when(new ShipOrderCommand(orderId)) + .expectEvents(new OrderShippedEvent(orderId)); } } \ No newline at end of file From 0a64e26a8fc0e4121159d61a3bd42a419c1acc30 Mon Sep 17 00:00:00 2001 From: DOHA Date: Sat, 29 Dec 2018 20:29:20 +0200 Subject: [PATCH 029/139] cleanup --- .../src/main/java/com/baeldung/boot/Application.java | 2 +- .../com/baeldung/boot/controller/rest/WebController.java | 6 +++--- .../{org => com}/baeldung/boot/LoadContextTest.groovy | 4 ++-- .../{org => com}/baeldung/boot/WebControllerTest.groovy | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename spring-boot-testing/src/test/groovy/{org => com}/baeldung/boot/LoadContextTest.groovy (87%) rename spring-boot-testing/src/test/groovy/{org => com}/baeldung/boot/WebControllerTest.groovy (98%) diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java b/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java index c1b6558b26..cb0d0c1532 100644 --- a/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/Application.java @@ -1,4 +1,4 @@ -package org.baeldung.boot; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java index 5b65599e00..7247ca3dfa 100644 --- a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/WebController.java @@ -1,4 +1,6 @@ -package org.baeldung.boot.controller.rest; +package com.baeldung.boot.controller.rest; + +import java.util.Optional; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; @@ -9,8 +11,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import java.util.Optional; - @RestController @RequestMapping("/hello") public class WebController { diff --git a/spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy similarity index 87% rename from spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy index 2d4a7ca2cf..85b0a4b89b 100644 --- a/spring-boot-testing/src/test/groovy/org/baeldung/boot/LoadContextTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy @@ -1,6 +1,6 @@ -package org.baeldung.boot +package com.baeldung.boot -import org.baeldung.boot.controller.rest.WebController +import com.baeldung.boot.controller.rest.WebController import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import spock.lang.Narrative diff --git a/spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy similarity index 98% rename from spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy index fe1b34ab8c..119992acc3 100644 --- a/spring-boot-testing/src/test/groovy/org/baeldung/boot/WebControllerTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy @@ -1,4 +1,4 @@ -package org.baeldung.boot +package com.baeldung.boot import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc From b4ff5c46f08a21ea01ffdca6859286a3e351bdb3 Mon Sep 17 00:00:00 2001 From: amit2103 Date: Sun, 30 Dec 2018 01:19:12 +0530 Subject: [PATCH 030/139] [BAEL-11402] - Moved articles out of core-java (part 3) --- core-java-io/README.md | 2 + core-java-io/pom.xml | 14 +++++ .../com/baeldung/extension/Extension.java | 0 .../baeldung/extension/ExtensionUnitTest.java | 0 .../java/mimetype/MimeTypeUnitTest.java | 0 .../src/test/resources/META-INF/mime.types | 0 .../src/test/resources/product.png | Bin core-java-security/README.md | 11 ++++ core-java-security/pom.xml | 55 ++++++++++++++++++ .../java/com/baeldung/cipher/Encryptor.java | 0 .../encrypt/FileEncrypterDecrypter.java | 0 .../com/baeldung/hashing/SHA256Hashing.java | 0 .../com/baeldung/keystore/JavaKeyStore.java | 0 .../passwordhashing/PBKDF2Hasher.java | 0 .../passwordhashing/SHA512Hasher.java | 0 .../passwordhashing/SimplePBKDF2Hasher.java | 0 .../com/baeldung/ssl/SecureConnection.java | 0 .../baeldung/ssl/example/SimpleClient.java | 0 .../baeldung/ssl/example/SimpleServer.java | 0 .../src/main/resources/logback.xml | 19 ++++++ .../baeldung/cipher/EncryptorUnitTest.java | 0 ...FileEncrypterDecrypterIntegrationTest.java | 0 .../hashing/SHA256HashingUnitTest.java | 0 .../keystore/JavaKeyStoreUnitTest.java | 0 .../passwordhashing/PBKDF2HasherUnitTest.java | 0 .../passwordhashing/SHA512HasherUnitTest.java | 0 .../baeldung/java/md5/JavaMD5UnitTest.java | 0 .../src/test/resources/test_md5.txt | 0 core-java/README.md | 9 --- core-java/pom.xml | 27 --------- guava/README.md | 1 - pom.xml | 2 + 32 files changed, 103 insertions(+), 37 deletions(-) rename {core-java => core-java-io}/src/main/java/com/baeldung/extension/Extension.java (100%) rename {core-java => core-java-io}/src/test/java/com/baeldung/extension/ExtensionUnitTest.java (100%) rename {core-java => core-java-io}/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java (100%) rename {core-java => core-java-io}/src/test/resources/META-INF/mime.types (100%) rename {core-java => core-java-io}/src/test/resources/product.png (100%) create mode 100644 core-java-security/README.md create mode 100644 core-java-security/pom.xml rename {core-java => core-java-security}/src/main/java/com/baeldung/cipher/Encryptor.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/hashing/SHA256Hashing.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/keystore/JavaKeyStore.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/ssl/SecureConnection.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/ssl/example/SimpleClient.java (100%) rename {core-java => core-java-security}/src/main/java/com/baeldung/ssl/example/SimpleServer.java (100%) create mode 100644 core-java-security/src/main/resources/logback.xml rename {core-java => core-java-security}/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java (100%) rename {core-java => core-java-security}/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java (100%) rename {core-java => core-java-security}/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java (100%) rename {core-java => core-java-security}/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java (100%) rename {core-java => core-java-security}/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java (100%) rename {core-java => core-java-security}/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java (100%) rename {core-java => core-java-security}/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java (100%) rename {core-java => core-java-security}/src/test/resources/test_md5.txt (100%) diff --git a/core-java-io/README.md b/core-java-io/README.md index 3d028783ed..2ad980ca6a 100644 --- a/core-java-io/README.md +++ b/core-java-io/README.md @@ -35,3 +35,5 @@ - [Guide to Java OutputStream](https://www.baeldung.com/java-outputstream) - [Reading a CSV File into an Array](https://www.baeldung.com/java-csv-file-array) - [Guide to BufferedReader](https://www.baeldung.com/java-buffered-reader) +- [How to Get the File Extension of a File in Java](http://www.baeldung.com/java-file-extension) +- [Getting a File’s Mime Type in Java](http://www.baeldung.com/java-file-mime-type) \ No newline at end of file diff --git a/core-java-io/pom.xml b/core-java-io/pom.xml index ac5f1f7c2e..1f2d52de81 100644 --- a/core-java-io/pom.xml +++ b/core-java-io/pom.xml @@ -160,6 +160,17 @@ ${opencsv.version} test + + + org.apache.tika + tika-core + ${tika.version} + + + net.sf.jmimemagic + jmimemagic + ${jmime-magic.version} + @@ -264,6 +275,9 @@ 2.1.0.1 1.19 2.4.5 + + 1.18 + 0.1.5 \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/extension/Extension.java b/core-java-io/src/main/java/com/baeldung/extension/Extension.java similarity index 100% rename from core-java/src/main/java/com/baeldung/extension/Extension.java rename to core-java-io/src/main/java/com/baeldung/extension/Extension.java diff --git a/core-java/src/test/java/com/baeldung/extension/ExtensionUnitTest.java b/core-java-io/src/test/java/com/baeldung/extension/ExtensionUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/extension/ExtensionUnitTest.java rename to core-java-io/src/test/java/com/baeldung/extension/ExtensionUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java b/core-java-io/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java rename to core-java-io/src/test/java/com/baeldung/java/mimetype/MimeTypeUnitTest.java diff --git a/core-java/src/test/resources/META-INF/mime.types b/core-java-io/src/test/resources/META-INF/mime.types similarity index 100% rename from core-java/src/test/resources/META-INF/mime.types rename to core-java-io/src/test/resources/META-INF/mime.types diff --git a/core-java/src/test/resources/product.png b/core-java-io/src/test/resources/product.png similarity index 100% rename from core-java/src/test/resources/product.png rename to core-java-io/src/test/resources/product.png diff --git a/core-java-security/README.md b/core-java-security/README.md new file mode 100644 index 0000000000..415171094b --- /dev/null +++ b/core-java-security/README.md @@ -0,0 +1,11 @@ +## Core Java Security + +### Relevant Articles: +- [MD5 Hashing in Java](http://www.baeldung.com/java-md5) +- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class) +- [Introduction to SSL in Java](http://www.baeldung.com/java-ssl) +- [Java KeyStore API](http://www.baeldung.com/java-keystore) +- [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream) +- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) +- [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) +- [SHA-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) \ No newline at end of file diff --git a/core-java-security/pom.xml b/core-java-security/pom.xml new file mode 100644 index 0000000000..cf91121465 --- /dev/null +++ b/core-java-security/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + com.baeldung + core-java-security + 0.1.0-SNAPSHOT + jar + core-java-security + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.bouncycastle + bcprov-jdk15on + ${bouncycastle.version} + + + + + + + 3.8.1 + 1.55 + 1.10 + + + 3.10.0 + + + + diff --git a/core-java/src/main/java/com/baeldung/cipher/Encryptor.java b/core-java-security/src/main/java/com/baeldung/cipher/Encryptor.java similarity index 100% rename from core-java/src/main/java/com/baeldung/cipher/Encryptor.java rename to core-java-security/src/main/java/com/baeldung/cipher/Encryptor.java diff --git a/core-java/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java b/core-java-security/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java similarity index 100% rename from core-java/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java rename to core-java-security/src/main/java/com/baeldung/encrypt/FileEncrypterDecrypter.java diff --git a/core-java/src/main/java/com/baeldung/hashing/SHA256Hashing.java b/core-java-security/src/main/java/com/baeldung/hashing/SHA256Hashing.java similarity index 100% rename from core-java/src/main/java/com/baeldung/hashing/SHA256Hashing.java rename to core-java-security/src/main/java/com/baeldung/hashing/SHA256Hashing.java diff --git a/core-java/src/main/java/com/baeldung/keystore/JavaKeyStore.java b/core-java-security/src/main/java/com/baeldung/keystore/JavaKeyStore.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keystore/JavaKeyStore.java rename to core-java-security/src/main/java/com/baeldung/keystore/JavaKeyStore.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/PBKDF2Hasher.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/SHA512Hasher.java diff --git a/core-java/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java b/core-java-security/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java similarity index 100% rename from core-java/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java rename to core-java-security/src/main/java/com/baeldung/passwordhashing/SimplePBKDF2Hasher.java diff --git a/core-java/src/main/java/com/baeldung/ssl/SecureConnection.java b/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/SecureConnection.java rename to core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java diff --git a/core-java/src/main/java/com/baeldung/ssl/example/SimpleClient.java b/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/example/SimpleClient.java rename to core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java diff --git a/core-java/src/main/java/com/baeldung/ssl/example/SimpleServer.java b/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java similarity index 100% rename from core-java/src/main/java/com/baeldung/ssl/example/SimpleServer.java rename to core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java diff --git a/core-java-security/src/main/resources/logback.xml b/core-java-security/src/main/resources/logback.xml new file mode 100644 index 0000000000..56af2d397e --- /dev/null +++ b/core-java-security/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java b/core-java-security/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java rename to core-java-security/src/test/java/com/baeldung/cipher/EncryptorUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java b/core-java-security/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java rename to core-java-security/src/test/java/com/baeldung/encrypt/FileEncrypterDecrypterIntegrationTest.java diff --git a/core-java/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java b/core-java-security/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java rename to core-java-security/src/test/java/com/baeldung/hashing/SHA256HashingUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java b/core-java-security/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java rename to core-java-security/src/test/java/com/baeldung/keystore/JavaKeyStoreUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java b/core-java-security/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java rename to core-java-security/src/test/java/com/baeldung/passwordhashing/PBKDF2HasherUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java b/core-java-security/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java rename to core-java-security/src/test/java/com/baeldung/passwordhashing/SHA512HasherUnitTest.java diff --git a/core-java/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java b/core-java-security/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java similarity index 100% rename from core-java/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java rename to core-java-security/src/test/java/org/baeldung/java/md5/JavaMD5UnitTest.java diff --git a/core-java/src/test/resources/test_md5.txt b/core-java-security/src/test/resources/test_md5.txt similarity index 100% rename from core-java/src/test/resources/test_md5.txt rename to core-java-security/src/test/resources/test_md5.txt diff --git a/core-java/README.md b/core-java/README.md index 21c58bb880..a3dd7fb2b7 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -5,7 +5,6 @@ ### Relevant Articles: - [Java Timer](http://www.baeldung.com/java-timer-and-timertask) - [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java) -- [MD5 Hashing in Java](http://www.baeldung.com/java-md5) - [How to Print Screen in Java](http://www.baeldung.com/print-screen-in-java) - [A Guide To Java Regular Expressions API](http://www.baeldung.com/regular-expressions-java) - [Getting Started with Java Properties](http://www.baeldung.com/java-properties) @@ -24,7 +23,6 @@ - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) - [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) -- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class) - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) - [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) - [Introduction to Javadoc](http://www.baeldung.com/javadoc) @@ -35,27 +33,20 @@ - [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) - [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle) - [Class Loaders in Java](http://www.baeldung.com/java-classloaders) -- [Introduction to SSL in Java](http://www.baeldung.com/java-ssl) -- [Java KeyStore API](http://www.baeldung.com/java-keystore) - [Double-Checked Locking with Singleton](http://www.baeldung.com/java-singleton-double-checked-locking) - [Guide to Java Clock Class](http://www.baeldung.com/java-clock) - [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class) -- [How to Get the File Extension of a File in Java](http://www.baeldung.com/java-file-extension) - [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler) -- [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream) - [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object) - [Guide to Java Instrumentation](http://www.baeldung.com/java-instrumentation) -- [Getting a File’s Mime Type in Java](http://www.baeldung.com/java-file-mime-type) - [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) - [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception) - [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) - [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) - [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) - [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) -- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) - [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) -- [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) - [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) - [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) - [Abstract Classes in Java](https://www.baeldung.com/java-abstract-class) diff --git a/core-java/pom.xml b/core-java/pom.xml index b4f0643aa8..6c58653d5a 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -24,11 +24,6 @@ commons-lang3 ${commons-lang3.version} - - org.bouncycastle - bcprov-jdk15on - ${bouncycastle.version} - org.unix4j unix4j-command @@ -75,12 +70,6 @@ ${assertj-core.version} test - - - commons-codec - commons-codec - ${commons-codec.version} - org.javamoney moneta @@ -126,17 +115,6 @@ h2 ${h2database.version} - - - org.apache.tika - tika-core - ${tika.version} - - - net.sf.jmimemagic - jmimemagic - ${jmime-magic.version} - org.javassist @@ -477,8 +455,6 @@ 3.5 - 1.55 - 1.10 2.5 3.6.1 1.0.3 @@ -509,9 +485,6 @@ 2.0.3.RELEASE 1.6.0 61.1 - - 1.18 - 0.1.5 3.21.0-GA diff --git a/guava/README.md b/guava/README.md index 0346d34903..60754dbe57 100644 --- a/guava/README.md +++ b/guava/README.md @@ -18,4 +18,3 @@ - [Hamcrest Text Matchers](http://www.baeldung.com/hamcrest-text-matchers) - [Quick Guide to the Guava RateLimiter](http://www.baeldung.com/guava-rate-limiter) - [Hamcrest File Matchers](https://www.baeldung.com/hamcrest-file-matchers) -- [SHA-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) diff --git a/pom.xml b/pom.xml index 923cbab302..e8ff86665c 100644 --- a/pom.xml +++ b/pom.xml @@ -383,6 +383,7 @@ core-java-concurrency-basic core-java-concurrency-collections core-java-io + core-java-security core-java-lang-syntax core-java-lang core-java-lang-oop @@ -1095,6 +1096,7 @@ core-java-concurrency-basic core-java-concurrency-collections core-java-io + core-java-security core-java-lang-syntax core-java-lang core-java-lang-oop From a89983a65cbf165f0e18889b6e43b1a7ed686dd3 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Sun, 30 Dec 2018 14:19:24 +0400 Subject: [PATCH 031/139] move unmodifiable set code to java 9 module --- .../com/baeldung/java9}/set/UnmodifiableSet.java | 6 +++--- .../java/com/baeldung/java9/SetExamplesUnitTest.java | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) rename {core-java-collections/src/main/java/com/baeldung => core-java-9/src/main/java/com/baeldung/java9}/set/UnmodifiableSet.java (88%) diff --git a/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java b/core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java similarity index 88% rename from core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java rename to core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java index 06f477c50a..7dbcd2a3a3 100644 --- a/core-java-collections/src/main/java/com/baeldung/set/UnmodifiableSet.java +++ b/core-java-9/src/main/java/com/baeldung/java9/set/UnmodifiableSet.java @@ -1,4 +1,4 @@ -package com.baeldung.set; +package com.baeldung.java9.set; import com.google.common.collect.ImmutableSet; @@ -21,8 +21,8 @@ public class UnmodifiableSet { } private static void java9Of() { - //Set immutable = Set.of("Canada", "USA"); - //System.out.println(immutable); + Set immutable = Set.of("Canada", "USA"); + System.out.println(immutable); } private static void guavaOf() { diff --git a/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java b/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java index 9e7e8e6e4b..28e71affcc 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/SetExamplesUnitTest.java @@ -1,5 +1,7 @@ package com.baeldung.java9; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import org.junit.Test; @@ -23,4 +25,14 @@ public class SetExamplesUnitTest { Set intSet = Set.of(intArray); assertEquals(intSet.size(), intArray.length); } + + @Test(expected = UnsupportedOperationException.class) + public void testUnmodifiableSet() { + Set set = new HashSet<>(); + set.add("Canada"); + set.add("USA"); + + Set unmodifiableSet = Collections.unmodifiableSet(set); + unmodifiableSet.add("Costa Rica"); + } } From eb4928b972264c86472576a1673fa7245431a740 Mon Sep 17 00:00:00 2001 From: amit2103 Date: Sun, 30 Dec 2018 16:30:36 +0530 Subject: [PATCH 032/139] [BAEL-11403] - Moved articles out of core-java (part 4) --- core-java-collections/README.md | 3 +- .../baeldung/iteratorguide/IteratorGuide.java | 0 core-java/README.md | 11 --- .../StringReplaceAndRemoveUnitTest.java | 83 ------------------- java-dates/README.md | 2 + .../zoneddatetime/OffsetDateTimeExample.java | 0 .../zoneddatetime/OffsetTimeExample.java | 0 .../zoneddatetime/ZoneDateTimeExample.java | 0 .../com/baeldung/date/DateDiffUnitTest.java | 2 + .../SimpleDateFormatUnitTest.java | 0 .../OffsetDateTimeExampleUnitTest.java | 0 .../OffsetTimeExampleUnitTest.java | 0 .../ZoneDateTimeExampleUnitTest.java | 0 java-numbers/README.md | 6 ++ .../java/com/baeldung/area/circle/Circle.java | 0 .../com/baeldung/area/circle/CircleArea.java | 0 .../root/calculator/NthRootCalculator.java | 0 .../java/com/baeldung/nth/root/main/Main.java | 0 .../DecimalFormatExamplesUnitTest.java | 0 .../com/baeldung/java/math/MathUnitTest.java | 0 .../calculator/NthRootCalculatorUnitTest.java | 0 .../baeldung/nth/root/main/MainUnitTest.java | 0 .../RemovingDecimalsManualTest.java | 0 .../RemovingDecimalsUnitTest.java | 0 java-strings/README.md | 2 + .../string/AppendCharAtPositionX.java | 0 .../string/AppendCharAtPositionXUnitTest.java | 0 .../DateToStringFormatterUnitTest.java | 9 +- 28 files changed, 19 insertions(+), 99 deletions(-) rename {core-java => core-java-collections}/src/main/java/com/baeldung/iteratorguide/IteratorGuide.java (100%) delete mode 100644 core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java rename {core-java => java-dates}/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java (100%) rename {core-java => java-dates}/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java (100%) rename {core-java => java-dates}/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java (100%) rename {core-java => java-dates}/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java (100%) rename {core-java => java-dates}/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java (100%) rename {core-java => java-dates}/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java (100%) rename {core-java => java-dates}/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java (100%) rename {core-java => java-numbers}/src/main/java/com/baeldung/area/circle/Circle.java (100%) rename {core-java => java-numbers}/src/main/java/com/baeldung/area/circle/CircleArea.java (100%) rename {core-java => java-numbers}/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java (100%) rename {core-java => java-numbers}/src/main/java/com/baeldung/nth/root/main/Main.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/java/math/MathUnitTest.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java (100%) rename {core-java => java-strings}/src/main/java/com/baeldung/string/AppendCharAtPositionX.java (100%) rename {core-java => java-strings}/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java (100%) diff --git a/core-java-collections/README.md b/core-java-collections/README.md index 15be81156c..71d4e6b614 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -28,4 +28,5 @@ - [Combining Different Types of Collections in Java](https://www.baeldung.com/java-combine-collections) - [Sorting in Java](http://www.baeldung.com/java-sorting) - [Join and Split Arrays and Collections in Java](http://www.baeldung.com/java-join-and-split) -- [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) \ No newline at end of file +- [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) +- [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/iteratorguide/IteratorGuide.java b/core-java-collections/src/main/java/com/baeldung/iteratorguide/IteratorGuide.java similarity index 100% rename from core-java/src/main/java/com/baeldung/iteratorguide/IteratorGuide.java rename to core-java-collections/src/main/java/com/baeldung/iteratorguide/IteratorGuide.java diff --git a/core-java/README.md b/core-java/README.md index 21c58bb880..4f03bac732 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -23,13 +23,10 @@ - [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) -- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) - [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class) - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) -- [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) -- [A Practical Guide to DecimalFormat](http://www.baeldung.com/java-decimalformat) - [How to Detect the OS Using Java](http://www.baeldung.com/java-detect-os) - [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) - [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid) @@ -48,19 +45,11 @@ - [Getting a File’s Mime Type in Java](http://www.baeldung.com/java-file-mime-type) - [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) - [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception) -- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) -- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) -- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) -- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) - [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) -- [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) - [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures) -- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) - [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) - [Abstract Classes in Java](https://www.baeldung.com/java-abstract-class) - [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) -- [Calculate the Area of a Circle in Java](https://www.baeldung.com/java-calculate-circle-area) -- [A Guide to the Java Math Class](https://www.baeldung.com/java-lang-math) - [Graphs in Java](https://www.baeldung.com/java-graphs) - [Console I/O in Java](http://www.baeldung.com/java-console-input-output) diff --git a/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java b/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java deleted file mode 100644 index d952d2383b..0000000000 --- a/core-java/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.baeldung.string; - - -import org.apache.commons.lang3.StringUtils; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class StringReplaceAndRemoveUnitTest { - - - @Test - public void givenTestStrings_whenReplace_thenProcessedString() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - String processed = master.replace(target, replacement); - assertTrue(processed.contains(replacement)); - assertFalse(processed.contains(target)); - - } - - @Test - public void givenTestStrings_whenReplaceAll_thenProcessedString() { - - String master2 = "Welcome to Baeldung, Hello World Baeldung"; - String regexTarget= "(Baeldung)$"; - String replacement = "Java"; - String processed2 = master2.replaceAll(regexTarget, replacement); - assertTrue(processed2.endsWith("Java")); - - } - - @Test - public void givenTestStrings_whenStringBuilderMethods_thenProcessedString() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - - int startIndex = master.indexOf(target); - int stopIndex = startIndex + target.length(); - - StringBuilder builder = new StringBuilder(master); - - - builder.delete(startIndex, stopIndex); - assertFalse(builder.toString().contains(target)); - - - builder.replace(startIndex, stopIndex, replacement); - assertTrue(builder.toString().contains(replacement)); - - - } - - - @Test - public void givenTestStrings_whenStringUtilsMethods_thenProcessedStrings() { - - String master = "Hello World Baeldung!"; - String target = "Baeldung"; - String replacement = "Java"; - - String processed = StringUtils.replace(master, target, replacement); - assertTrue(processed.contains(replacement)); - - String master2 = "Hello World Baeldung!"; - String target2 = "baeldung"; - String processed2 = StringUtils.replaceIgnoreCase(master2, target2, replacement); - assertFalse(processed2.contains(target)); - - } - - - - - - - -} diff --git a/java-dates/README.md b/java-dates/README.md index 21e54082f4..ac3166d938 100644 --- a/java-dates/README.md +++ b/java-dates/README.md @@ -26,3 +26,5 @@ - [Format ZonedDateTime to String](https://www.baeldung.com/java-format-zoned-datetime-string) - [Convert Between java.time.Instant and java.sql.Timestamp](https://www.baeldung.com/java-time-instant-to-java-sql-timestamp) - [Convert between String and Timestamp](https://www.baeldung.com/java-string-to-timestamp) +- [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) +- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetDateTimeExample.java diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/OffsetTimeExample.java diff --git a/core-java/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java b/java-dates/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java similarity index 100% rename from core-java/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java rename to java-dates/src/main/java/com/baeldung/zoneddatetime/ZoneDateTimeExample.java diff --git a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java index 1234a700de..a35699e469 100644 --- a/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java +++ b/java-dates/src/test/java/com/baeldung/date/DateDiffUnitTest.java @@ -8,6 +8,8 @@ import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.Locale; diff --git a/core-java/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java b/java-dates/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java rename to java-dates/src/test/java/com/baeldung/simpledateformat/SimpleDateFormatUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetDateTimeExampleUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/OffsetTimeExampleUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java b/java-dates/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java rename to java-dates/src/test/java/com/baeldung/zoneddatetime/ZoneDateTimeExampleUnitTest.java diff --git a/java-numbers/README.md b/java-numbers/README.md index 1138d9a74c..2b1131f325 100644 --- a/java-numbers/README.md +++ b/java-numbers/README.md @@ -13,3 +13,9 @@ - [Find All Pairs of Numbers in an Array That Add Up to a Given Sum](http://www.baeldung.com/java-algorithm-number-pairs-sum) - [Java – Random Long, Float, Integer and Double](http://www.baeldung.com/java-generate-random-long-float-integer-double) - [Using Math.sin with Degrees](https://www.baeldung.com/java-math-sin-degrees) +- [A Practical Guide to DecimalFormat](http://www.baeldung.com/java-decimalformat) +- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) +- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) +- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) +- [Calculate the Area of a Circle in Java](https://www.baeldung.com/java-calculate-circle-area) +- [A Guide to the Java Math Class](https://www.baeldung.com/java-lang-math) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/area/circle/Circle.java b/java-numbers/src/main/java/com/baeldung/area/circle/Circle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/area/circle/Circle.java rename to java-numbers/src/main/java/com/baeldung/area/circle/Circle.java diff --git a/core-java/src/main/java/com/baeldung/area/circle/CircleArea.java b/java-numbers/src/main/java/com/baeldung/area/circle/CircleArea.java similarity index 100% rename from core-java/src/main/java/com/baeldung/area/circle/CircleArea.java rename to java-numbers/src/main/java/com/baeldung/area/circle/CircleArea.java diff --git a/core-java/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java b/java-numbers/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java rename to java-numbers/src/main/java/com/baeldung/nth/root/calculator/NthRootCalculator.java diff --git a/core-java/src/main/java/com/baeldung/nth/root/main/Main.java b/java-numbers/src/main/java/com/baeldung/nth/root/main/Main.java similarity index 100% rename from core-java/src/main/java/com/baeldung/nth/root/main/Main.java rename to java-numbers/src/main/java/com/baeldung/nth/root/main/Main.java diff --git a/core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java b/java-numbers/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java rename to java-numbers/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/java/math/MathUnitTest.java b/java-numbers/src/test/java/com/baeldung/java/math/MathUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/java/math/MathUnitTest.java rename to java-numbers/src/test/java/com/baeldung/java/math/MathUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java b/java-numbers/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java rename to java-numbers/src/test/java/com/baeldung/nth/root/calculator/NthRootCalculatorUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java b/java-numbers/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java rename to java-numbers/src/test/java/com/baeldung/nth/root/main/MainUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java b/java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java rename to java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsManualTest.java diff --git a/core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java b/java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java rename to java-numbers/src/test/java/com/baeldung/removingdecimals/RemovingDecimalsUnitTest.java diff --git a/java-strings/README.md b/java-strings/README.md index 60131e392d..fa048dbb5a 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -45,3 +45,5 @@ - [Remove or Replace part of a String in Java](https://www.baeldung.com/java-remove-replace-string-part) - [Replace a Character at a Specific Index in a String in Java](https://www.baeldung.com/java-replace-character-at-index) - [Convert a Comma Separated String to a List in Java](https://www.baeldung.com/java-string-with-separator-to-list) +- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) +- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/string/AppendCharAtPositionX.java b/java-strings/src/main/java/com/baeldung/string/AppendCharAtPositionX.java similarity index 100% rename from core-java/src/main/java/com/baeldung/string/AppendCharAtPositionX.java rename to java-strings/src/main/java/com/baeldung/string/AppendCharAtPositionX.java diff --git a/core-java/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java b/java-strings/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java rename to java-strings/src/test/java/com/baeldung/string/AppendCharAtPositionXUnitTest.java diff --git a/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java b/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java index f236c641c3..d760510c73 100644 --- a/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/formatter/DateToStringFormatterUnitTest.java @@ -1,7 +1,6 @@ package com.baeldung.string.formatter; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.junit.Assert.assertEquals; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -11,9 +10,11 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; +import org.junit.BeforeClass; +import org.junit.Test; public class DateToStringFormatterUnitTest { @@ -40,7 +41,7 @@ public class DateToStringFormatterUnitTest { @Test public void whenDateConvertedUsingDateFormatToString_thenCorrect() { String formattedDate = DateFormat - .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT) + .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.US) .format(date); assertEquals(EXPECTED_STRING_DATE, formattedDate); From 3bdd542dbf78acb998d64527ba49120c6eea3c9a Mon Sep 17 00:00:00 2001 From: Erhan KARAKAYA Date: Mon, 31 Dec 2018 03:48:20 +0300 Subject: [PATCH 033/139] Added @Value for map examples --- .../java/com/baeldung/value/ValuesApp.java | 28 +++++++++++++++++++ .../src/main/resources/values.properties | 3 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java index f525dfde89..33592ae38a 100644 --- a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java +++ b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java @@ -45,6 +45,27 @@ public class ValuesApp { @Value("#{'${listOfValues}'.split(',')}") private List valuesList; + + @Value("#{${valuesMap}}") + private Map valuesMap; + + @Value("#{${valuesMap}.key1}") + private Integer valuesMapKey1; + + @Value("#{${valuesMap}['unknownKey']}") + private Integer unknownMapKey; + + @Value("#{${unknownMap : {key1:'1', key2 : '2'}}}") + private Map unknownMap; + + @Value("#{${valuesMap}['unknownKey'] ?: 5}") + private Integer unknownMapKeyWithDefaultValue; + + @Value("#{${valuesMap}.?[value>'1']}") + private Map valuesMapFiltered; + + @Value("#{systemProperties}") + private Map systemPropertiesMap; public static void main(String[] args) { System.setProperty("systemValue", "Some system parameter value"); @@ -69,5 +90,12 @@ public class ValuesApp { System.out.println(spelSomeDefault); System.out.println(someBeanValue); System.out.println(valuesList); + System.out.println(valuesMap); + System.out.println(valuesMapKey1); + System.out.println(unknownMapKey); + System.out.println(unknownMap); + System.out.println(unknownMapKeyWithDefaultValue); + System.out.println(valuesMapFiltered); + System.out.println(systemPropertiesMap); } } diff --git a/spring-core/src/main/resources/values.properties b/spring-core/src/main/resources/values.properties index d7d61b8ee8..c6db5873fb 100644 --- a/spring-core/src/main/resources/values.properties +++ b/spring-core/src/main/resources/values.properties @@ -1,3 +1,4 @@ value.from.file=Value got from the file priority=Properties file -listOfValues=A,B,C \ No newline at end of file +listOfValues=A,B,C +valuesMap={key1:'1', key2 : '2', key3 : '3'} \ No newline at end of file From 90037051b917432008c0a39eca55cc6d86e109cb Mon Sep 17 00:00:00 2001 From: Erhan KARAKAYA Date: Mon, 31 Dec 2018 04:01:27 +0300 Subject: [PATCH 034/139] Added missing import --- spring-core/src/main/java/com/baeldung/value/ValuesApp.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java index 33592ae38a..80893c1adf 100644 --- a/spring-core/src/main/java/com/baeldung/value/ValuesApp.java +++ b/spring-core/src/main/java/com/baeldung/value/ValuesApp.java @@ -2,6 +2,7 @@ package com.baeldung.value; import java.util.Arrays; import java.util.List; +import java.util.Map; import javax.annotation.PostConstruct; From 6c6046200060f121f040c16db6c8d7bdf7fa1922 Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Mon, 31 Dec 2018 10:07:38 +0100 Subject: [PATCH 035/139] added README --- akka-http/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 akka-http/README.md diff --git a/akka-http/README.md b/akka-http/README.md new file mode 100644 index 0000000000..583d2efa74 --- /dev/null +++ b/akka-http/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Akka HTTP](https://www.baeldung.com/akka-http) From 0cf67f5dbef3d8c1ef17d2478654469f17fb2472 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Mon, 31 Dec 2018 13:45:58 +0100 Subject: [PATCH 036/139] BAEL-2435 Change dependency Change the autoconfigure dependency to the starter dependency of Axon --- axon/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axon/pom.xml b/axon/pom.xml index 03d2499a99..598dc820e5 100644 --- a/axon/pom.xml +++ b/axon/pom.xml @@ -16,7 +16,7 @@ org.axonframework - axon-spring-boot-autoconfigure + axon-spring-boot-starter ${axon.version} From f757eba28b25d8d7807a23c1748230a096f7df97 Mon Sep 17 00:00:00 2001 From: DOHA Date: Mon, 31 Dec 2018 16:50:19 +0200 Subject: [PATCH 037/139] adding security for testing purpose --- spring-boot-testing/pom.xml | 32 +++++++++++++----- .../com/baeldung/boot/SecurityConfig.java | 32 ++++++++++++++++++ .../boot/controller/rest/HomeController.java | 14 ++++++++ .../src/main/resources/application.properties | 4 +++ ...oovy => LoadContextIntegrationTest.groovy} | 2 +- ...vy => WebControllerIntegrationTest.groovy} | 6 ++-- .../boot/WebControllerTest.groovy alias | Bin 0 -> 217036 bytes 7 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java create mode 100644 spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java create mode 100644 spring-boot-testing/src/main/resources/application.properties rename spring-boot-testing/src/test/groovy/com/baeldung/boot/{LoadContextTest.groovy => LoadContextIntegrationTest.groovy} (91%) rename spring-boot-testing/src/test/groovy/com/baeldung/boot/{WebControllerTest.groovy => WebControllerIntegrationTest.groovy} (94%) create mode 100644 spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias diff --git a/spring-boot-testing/pom.xml b/spring-boot-testing/pom.xml index 2a498e54c5..dd40789604 100644 --- a/spring-boot-testing/pom.xml +++ b/spring-boot-testing/pom.xml @@ -23,6 +23,10 @@ org.springframework.boot spring-boot-starter-tomcat + + org.springframework.boot + spring-boot-starter-security + org.springframework.boot spring-boot-starter-test @@ -43,6 +47,13 @@ ${spock.version} test + + + io.rest-assured + rest-assured + test + + @@ -99,13 +110,23 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + + + + - autoconfiguration + integration @@ -118,13 +139,8 @@ test - - **/*LiveTest.java - **/*IntegrationTest.java - **/*IntTest.java - - **/AutoconfigurationTest.java + **/*IntegrationTest.java @@ -142,7 +158,7 @@ - org.baeldung.boot.Application + com.baeldung.boot.Application 2.2.4 1.2-groovy-2.4 diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java b/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java new file mode 100644 index 0000000000..61e86d01c5 --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java @@ -0,0 +1,32 @@ +//package com.baeldung.boot; +// +//import org.springframework.context.annotation.Configuration; +//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +// +// +//@Configuration +//@EnableWebSecurity +//public class SecurityConfig extends WebSecurityConfigurerAdapter { +// +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// auth.inMemoryAuthentication() +// .withUser("john") +// .password("{noop}123") +// .roles("USER"); +// } +// +// @Override +// protected void configure(HttpSecurity http) throws Exception { +// http.authorizeRequests() +// .antMatchers("/hello") +// .permitAll() +// .anyRequest() +// .authenticated() +// .and() +// .httpBasic(); +// } +//} \ No newline at end of file diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java new file mode 100644 index 0000000000..595c34254b --- /dev/null +++ b/spring-boot-testing/src/main/java/com/baeldung/boot/controller/rest/HomeController.java @@ -0,0 +1,14 @@ +package com.baeldung.boot.controller.rest; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HomeController { + + @GetMapping("/") + public String salutation() { + return "Welcome !"; + } + +} \ No newline at end of file diff --git a/spring-boot-testing/src/main/resources/application.properties b/spring-boot-testing/src/main/resources/application.properties new file mode 100644 index 0000000000..e378aacdd5 --- /dev/null +++ b/spring-boot-testing/src/main/resources/application.properties @@ -0,0 +1,4 @@ + +# security +spring.security.user.name=john +spring.security.user.password=123 \ No newline at end of file diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy similarity index 91% rename from spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy index 85b0a4b89b..8bfc86685c 100644 --- a/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy @@ -10,7 +10,7 @@ import spock.lang.Title @Title("Application Specification") @Narrative("Specification which beans are expected") @SpringBootTest -class LoadContextTest extends Specification { +class LoadContextIntegrationTest extends Specification { @Autowired(required = false) private WebController webController diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy similarity index 94% rename from spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy index 119992acc3..17c60376ed 100644 --- a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy @@ -12,9 +12,9 @@ import spock.lang.Title @Title("WebController Specification") @Narrative("The Specification of the behaviour of the WebController. It can greet a person, change the name and reset it to 'world'") -@AutoConfigureMockMvc -@WebMvcTest -class WebControllerTest extends Specification { +@AutoConfigureMockMvc(secure=false) +@WebMvcTest() +class WebControllerIntegrationTest extends Specification { @Autowired private MockMvc mvc diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy alias new file mode 100644 index 0000000000000000000000000000000000000000..f2fc2f48e27bcf946a76f67ec7bacd1a2c3dd394 GIT binary patch literal 217036 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

l- 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

L?r!fZ) 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 Date: Mon, 31 Dec 2018 16:51:27 +0200 Subject: [PATCH 038/139] exclude auto-configuration --- .../resources/application-test.properties | 3 ++ .../ExcludeAutoConfig1IntegrationTest.java | 26 ++++++++++++++++ .../ExcludeAutoConfig2IntegrationTest.java | 26 ++++++++++++++++ .../ExcludeAutoConfig3IntegrationTest.java | 27 +++++++++++++++++ .../ExcludeAutoConfig4IntegrationTest.java | 22 ++++++++++++++ .../autoconfig/exclude/TestApplication.java | 13 ++++++++ .../boot/SpringContextIntegrationTest.java | 15 ++++++++++ .../autoconfig/AutoConfigIntegrationTest.java | 30 +++++++++++++++++++ 8 files changed, 162 insertions(+) create mode 100644 spring-boot-testing/src/main/resources/application-test.properties create mode 100644 spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java create mode 100644 spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java diff --git a/spring-boot-testing/src/main/resources/application-test.properties b/spring-boot-testing/src/main/resources/application-test.properties new file mode 100644 index 0000000000..8d5e86ba26 --- /dev/null +++ b/spring-boot-testing/src/main/resources/application-test.properties @@ -0,0 +1,3 @@ + +# test properties +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration \ No newline at end of file diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java new file mode 100644 index 0000000000..a4a29cddf3 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig1IntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@TestPropertySource(properties = "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration") +public class ExcludeAutoConfig1IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java new file mode 100644 index 0000000000..cdf79b159c --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig2IntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@ActiveProfiles("test") +public class ExcludeAutoConfig2IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java new file mode 100644 index 0000000000..0e45d1e9e5 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig3IntegrationTest.java @@ -0,0 +1,27 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +@EnableAutoConfiguration(exclude=SecurityAutoConfiguration.class) +public class ExcludeAutoConfig3IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java new file mode 100644 index 0000000000..8429aed6cd --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/ExcludeAutoConfig4IntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.autoconfig.exclude; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT) +public class ExcludeAutoConfig4IntegrationTest { + + @Test + public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java new file mode 100644 index 0000000000..7c162f85ab --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/autoconfig/exclude/TestApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.autoconfig.exclude; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; + +@SpringBootApplication(scanBasePackages="com.baeldung.boot", exclude=SecurityAutoConfiguration.class) +public class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java new file mode 100644 index 0000000000..63ab07fdb7 --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/boot/SpringContextIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.boot; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) +public class SpringContextIntegrationTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java b/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java new file mode 100644 index 0000000000..fe71f44ddf --- /dev/null +++ b/spring-boot-testing/src/test/java/com/baeldung/boot/autoconfig/AutoConfigIntegrationTest.java @@ -0,0 +1,30 @@ +package com.baeldung.boot.autoconfig; + +import static org.junit.Assert.assertEquals; +import io.restassured.RestAssured; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) +public class AutoConfigIntegrationTest { + + @Test + public void givenNoAuthentication_whenAccessHome_thenUnauthorized() { + int statusCode = RestAssured.get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.UNAUTHORIZED.value(), statusCode); + } + + @Test + public void givenAuthentication_whenAccessHome_thenOK() { + int statusCode = RestAssured.given().auth().basic("john", "123").get("http://localhost:8080/").statusCode(); + assertEquals(HttpStatus.OK.value(), statusCode); + } +} From c39fe1c85ca175a028521f8bf77ef9a906e24a6f Mon Sep 17 00:00:00 2001 From: Markus Gulden <> Date: Tue, 1 Jan 2019 15:40:15 +0100 Subject: [PATCH 039/139] BAEL-2321 --- .../04_Custom/connect-distributed.properties | 88 ----------------- .../04_Custom/connect-mongodb-sink.json | 30 +++--- .../04_Custom/connect-mqtt-source.json | 8 +- .../04_Custom/docker-compose.yaml | 94 +++++++++++++++++++ 4 files changed, 110 insertions(+), 110 deletions(-) delete mode 100644 libraries-data/src/main/kafka-connect/04_Custom/connect-distributed.properties create mode 100644 libraries-data/src/main/kafka-connect/04_Custom/docker-compose.yaml diff --git a/libraries-data/src/main/kafka-connect/04_Custom/connect-distributed.properties b/libraries-data/src/main/kafka-connect/04_Custom/connect-distributed.properties deleted file mode 100644 index 5b91baddbd..0000000000 --- a/libraries-data/src/main/kafka-connect/04_Custom/connect-distributed.properties +++ /dev/null @@ -1,88 +0,0 @@ -## -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -## - -# This file contains some of the configurations for the Kafka Connect distributed worker. This file is intended -# to be used with the examples, and some settings may differ from those used in a production system, especially -# the `bootstrap.servers` and those specifying replication factors. - -# A list of host/port pairs to use for establishing the initial connection to the Kafka cluster. -bootstrap.servers=localhost:9092 - -# unique name for the cluster, used in forming the Connect cluster group. Note that this must not conflict with consumer group IDs -group.id=connect-cluster - -# The converters specify the format of data in Kafka and how to translate it into Connect data. Every Connect user will -# need to configure these based on the format they want their data in when loaded from or stored into Kafka -key.converter=org.apache.kafka.connect.json.JsonConverter -value.converter=org.apache.kafka.connect.json.JsonConverter -# Converter-specific settings can be passed in by prefixing the Converter's setting with the converter we want to apply -# it to -key.converter.schemas.enable=true -value.converter.schemas.enable=true - -# Topic to use for storing offsets. This topic should have many partitions and be replicated and compacted. -# Kafka Connect will attempt to create the topic automatically when needed, but you can always manually create -# the topic before starting Kafka Connect if a specific topic configuration is needed. -# Most users will want to use the built-in default replication factor of 3 or in some cases even specify a larger value. -# Since this means there must be at least as many brokers as the maximum replication factor used, we'd like to be able -# to run this example on a single-broker cluster and so here we instead set the replication factor to 1. -offset.storage.topic=connect-offsets -offset.storage.replication.factor=1 -#offset.storage.partitions=25 - -# Topic to use for storing connector and task configurations; note that this should be a single partition, highly replicated, -# and compacted topic. Kafka Connect will attempt to create the topic automatically when needed, but you can always manually create -# the topic before starting Kafka Connect if a specific topic configuration is needed. -# Most users will want to use the built-in default replication factor of 3 or in some cases even specify a larger value. -# Since this means there must be at least as many brokers as the maximum replication factor used, we'd like to be able -# to run this example on a single-broker cluster and so here we instead set the replication factor to 1. -config.storage.topic=connect-configs -config.storage.replication.factor=1 - -# Topic to use for storing statuses. This topic can have multiple partitions and should be replicated and compacted. -# Kafka Connect will attempt to create the topic automatically when needed, but you can always manually create -# the topic before starting Kafka Connect if a specific topic configuration is needed. -# Most users will want to use the built-in default replication factor of 3 or in some cases even specify a larger value. -# Since this means there must be at least as many brokers as the maximum replication factor used, we'd like to be able -# to run this example on a single-broker cluster and so here we instead set the replication factor to 1. -status.storage.topic=connect-status -status.storage.replication.factor=1 -#status.storage.partitions=5 - -# Flush much faster than normal, which is useful for testing/debugging -offset.flush.interval.ms=10000 - -# These are provided to inform the user about the presence of the REST host and port configs -# Hostname & Port for the REST API to listen on. If this is set, it will bind to the interface used to listen to requests. -#rest.host.name= -#rest.port=8083 - -# The Hostname & Port that will be given out to other workers to connect to i.e. URLs that are routable from other servers. -#rest.advertised.host.name= -#rest.advertised.port= - -# Set to a list of filesystem paths separated by commas (,) to enable class loading isolation for plugins -# (connectors, converters, transformations). The list should consist of top level directories that include -# any combination of: -# a) directories immediately containing jars with plugins and their dependencies -# b) uber-jars with plugins and their dependencies -# c) directories immediately containing the package directory structure of classes of plugins and their dependencies -# Examples: -# plugin.path=/usr/local/share/java,/usr/local/share/kafka/plugins,/opt/connectors, -# Replace the relative path below with an absolute path if you are planning to start Kafka Connect from within a -# directory other than the home directory of Confluent Platform. -plugin.path=./share/java diff --git a/libraries-data/src/main/kafka-connect/04_Custom/connect-mongodb-sink.json b/libraries-data/src/main/kafka-connect/04_Custom/connect-mongodb-sink.json index 333768e4b7..852f400fc6 100644 --- a/libraries-data/src/main/kafka-connect/04_Custom/connect-mongodb-sink.json +++ b/libraries-data/src/main/kafka-connect/04_Custom/connect-mongodb-sink.json @@ -1,22 +1,14 @@ { - "firstName": "John", - "lastName": "Smith", - "age": 25, - "address": { - "streetAddress": "21 2nd Street", - "city": "New York", - "state": "NY", - "postalCode": "10021" - }, - "phoneNumber": [{ - "type": "home", - "number": "212 555-1234" - }, { - "type": "fax", - "number": "646 555-4567" - } - ], - "gender": { - "type": "male" + "name": "mongodb-sink", + "config": { + "connector.class": "at.grahsl.kafka.connect.mongodb.MongoDbSinkConnector", + "tasks.max": 1, + "topics": "connect-custom", + "mongodb.connection.uri": "mongodb://mongo-db/test?retryWrites=true", + "mongodb.collection": "MyCollection", + "key.converter": "org.apache.kafka.connect.json.JsonConverter", + "key.converter.schemas.enable": false, + "value.converter": "org.apache.kafka.connect.json.JsonConverter", + "value.converter.schemas.enable": false } } diff --git a/libraries-data/src/main/kafka-connect/04_Custom/connect-mqtt-source.json b/libraries-data/src/main/kafka-connect/04_Custom/connect-mqtt-source.json index 02d87c5ad7..c76d326c0a 100644 --- a/libraries-data/src/main/kafka-connect/04_Custom/connect-mqtt-source.json +++ b/libraries-data/src/main/kafka-connect/04_Custom/connect-mqtt-source.json @@ -3,9 +3,11 @@ "config": { "connector.class": "io.confluent.connect.mqtt.MqttSourceConnector", "tasks.max": 1, - "mqtt.server.uri": "ws://broker.hivemq.com:8000/mqtt", + "mqtt.server.uri": "tcp://mosquitto:1883", "mqtt.topics": "baeldung", "kafka.topic": "connect-custom", - "value.converter": "org.apache.kafka.connect.converters.ByteArrayConverter" + "value.converter": "org.apache.kafka.connect.converters.ByteArrayConverter", + "confluent.topic.bootstrap.servers": "kafka:9092", + "confluent.topic.replication.factor": 1 } -} +} \ No newline at end of file diff --git a/libraries-data/src/main/kafka-connect/04_Custom/docker-compose.yaml b/libraries-data/src/main/kafka-connect/04_Custom/docker-compose.yaml new file mode 100644 index 0000000000..26cd653335 --- /dev/null +++ b/libraries-data/src/main/kafka-connect/04_Custom/docker-compose.yaml @@ -0,0 +1,94 @@ +version: '3.3' + +services: + mosquitto: + image: eclipse-mosquitto:1.5.5 + hostname: mosquitto + container_name: mosquitto + expose: + - "1883" + ports: + - "1883:1883" + zookeeper: + image: zookeeper:3.4.9 + restart: unless-stopped + hostname: zookeeper + container_name: zookeeper + ports: + - "2181:2181" + environment: + ZOO_MY_ID: 1 + ZOO_PORT: 2181 + ZOO_SERVERS: server.1=zookeeper:2888:3888 + volumes: + - ./zookeeper/data:/data + - ./zookeeper/datalog:/datalog + kafka: + image: confluentinc/cp-kafka:5.1.0 + hostname: kafka + container_name: kafka + ports: + - "9092:9092" + environment: + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 + KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" + KAFKA_BROKER_ID: 1 + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + volumes: + - ./kafka/data:/var/lib/kafka/data + depends_on: + - zookeeper + kafka-connect: + image: confluentinc/cp-kafka-connect:5.1.0 + hostname: kafka-connect + container_name: kafka-connect + ports: + - "8083:8083" + environment: + CONNECT_BOOTSTRAP_SERVERS: "kafka:9092" + CONNECT_REST_ADVERTISED_HOST_NAME: connect + CONNECT_REST_PORT: 8083 + CONNECT_GROUP_ID: compose-connect-group + CONNECT_CONFIG_STORAGE_TOPIC: docker-connect-configs + CONNECT_OFFSET_STORAGE_TOPIC: docker-connect-offsets + CONNECT_STATUS_STORAGE_TOPIC: docker-connect-status + CONNECT_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter + CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter + CONNECT_INTERNAL_KEY_CONVERTER: "org.apache.kafka.connect.json.JsonConverter" + CONNECT_INTERNAL_VALUE_CONVERTER: "org.apache.kafka.connect.json.JsonConverter" + CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: "1" + CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: "1" + CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: "1" + CONNECT_PLUGIN_PATH: '/usr/share/java,/etc/kafka-connect/jars' + CONNECT_CONFLUENT_TOPIC_REPLICATION_FACTOR: 1 + volumes: + - /tmp/custom/jars:/etc/kafka-connect/jars + depends_on: + - zookeeper + - kafka + - mosquitto + mongo-db: + image: mongo:4.0.5 + hostname: mongo-db + container_name: mongo-db + expose: + - "27017" + ports: + - "27017:27017" + command: --bind_ip_all --smallfiles + volumes: + - ./mongo-db:/data + mongoclient: + image: mongoclient/mongoclient:2.2.0 + container_name: mongoclient + hostname: mongoclient + depends_on: + - mongo-db + ports: + - 3000:3000 + environment: + MONGO_URL: "mongodb://mongo-db:27017" + PORT: 3000 + expose: + - "3000" \ No newline at end of file From c560a37b70907834f90d73eca63c612e27cd1826 Mon Sep 17 00:00:00 2001 From: Loredana Date: Tue, 1 Jan 2019 22:44:53 +0200 Subject: [PATCH 040/139] add start class --- spring-boot-security/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index d5c7976ba2..b87189757a 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -66,4 +66,8 @@ + + com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication + + From 0d5483e1bf74b0d00aa314d7f8a84f5feb710e81 Mon Sep 17 00:00:00 2001 From: rahusriv Date: Wed, 2 Jan 2019 08:26:43 +0530 Subject: [PATCH 041/139] Rahul/multidimensional/pr3 (#6040) * Making examples simple * Changing variable names * Modificatons in naming * Giving extra spaces --- .../ArrayListOfArrayList.java | 21 ++++++++++--------- .../ThreeDimensionalArrayList.java | 10 ++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java b/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java index 2c3da7b1fc..e11f8e8ba0 100644 --- a/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java +++ b/core-java-collections-list/src/main/java/com/baeldung/list/multidimensional/ArrayListOfArrayList.java @@ -6,11 +6,11 @@ public class ArrayListOfArrayList { public static void main(String args[]) { - int numVertices = 3; - ArrayList> graph = new ArrayList<>(numVertices); + int vertexCount = 3; + ArrayList> graph = new ArrayList<>(vertexCount); //Initializing each element of ArrayList with ArrayList - for(int i=0; i< numVertices; i++) { + for(int i = 0; i< vertexCount; i++) { graph.add(new ArrayList()); } @@ -21,13 +21,14 @@ public class ArrayListOfArrayList { graph.get(1).add(0); graph.get(2).add(1); graph.get(0).add(2); - - //Printing all the edges - for(int vertexNo=0; vertexNo listOfVertices = graph.get(vertexNo); - for(int i=0; i > > space = new ArrayList<>(x_axis_length); //Initializing each element of ArrayList with ArrayList< ArrayList > - for(int i=0; i< x_axis_length; i++) { + for(int i = 0; i < x_axis_length; i++) { space.add(new ArrayList< ArrayList >(y_axis_length)); - for(int j =0; j< y_axis_length; j++) { + for(int j = 0; j < y_axis_length; j++) { space.get(i).add(new ArrayList(z_axis_length)); } } @@ -33,9 +33,9 @@ public class ThreeDimensionalArrayList { space.get(1).get(1).add(1,"Yellow"); //Printing colors for all the points - for(int i=0; i Date: Wed, 2 Jan 2019 13:36:50 +0200 Subject: [PATCH 042/139] Update README.md --- core-java/README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core-java/README.md b/core-java/README.md index 3c5d1941d6..03b77186b0 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -22,7 +22,6 @@ - [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri) - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) -- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) @@ -40,13 +39,7 @@ - [Common Java Exceptions](http://www.baeldung.com/java-common-exceptions) - [Throw Exception in Optional in Java 8](https://www.baeldung.com/java-optional-throw-exception) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) -- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) -- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root) -- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string) -- [ZoneOffset in Java](https://www.baeldung.com/java-zone-offset) - [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) -- [A Guide to SimpleDateFormat](https://www.baeldung.com/java-simple-date-format) -- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order) - [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) - [Abstract Classes in Java](https://www.baeldung.com/java-abstract-class) - [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) From e464591902afaa61de6035486a8240a87e046b38 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 14:39:01 +0200 Subject: [PATCH 043/139] Update README.md --- core-java-collections/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-collections/README.md b/core-java-collections/README.md index 71d4e6b614..1a90d01a82 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -29,4 +29,4 @@ - [Sorting in Java](http://www.baeldung.com/java-sorting) - [Join and Split Arrays and Collections in Java](http://www.baeldung.com/java-join-and-split) - [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) -- [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) \ No newline at end of file +- [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) From 1db24b5c06076b85d4a2c3ab4b3caddd74df8154 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 15:45:28 +0200 Subject: [PATCH 044/139] Update README.md --- core-java-8/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core-java-8/README.md b/core-java-8/README.md index e5fa953cc7..f9af585ab3 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -33,3 +33,7 @@ - [Java Primitives versus Objects](https://www.baeldung.com/java-primitives-vs-objects) - [How to Use if/else Logic in Java 8 Streams](https://www.baeldung.com/java-8-streams-if-else-logic) - [How to Replace Many if Statements in Java](https://www.baeldung.com/java-replace-if-statements) +- [Java @Override Annotation](https://www.baeldung.com/java-override) +- [Java @SuppressWarnings Annotation](https://www.baeldung.com/java-suppresswarnings) +- [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) +- [Java @Deprecated Annotation](https://www.baeldung.com/java-deprecated) From 75bf7ba5155da5fd1b8240080e35c4f0adb8781f Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Wed, 2 Jan 2019 22:11:21 +0530 Subject: [PATCH 045/139] BAEL-2536-check-for-a-panagram-string --- .../java/com/baeldung/string/Panagram.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 java-strings/src/main/java/com/baeldung/string/Panagram.java diff --git a/java-strings/src/main/java/com/baeldung/string/Panagram.java b/java-strings/src/main/java/com/baeldung/string/Panagram.java new file mode 100644 index 0000000000..d000b4455e --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/Panagram.java @@ -0,0 +1,60 @@ +package com.baeldung.string; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Panagram { + + public static boolean isPanagram(String str) { + if (str == null) + return false; + Boolean[] alphabetMarker = new Boolean[26]; + Arrays.fill(alphabetMarker, false); + int alphabetIndex = 0; + str = str.toUpperCase(); + for (int i = 0; i < str.length(); i++) { + if ('A' <= str.charAt(i) && str.charAt(i) <= 'Z') { + alphabetIndex = str.charAt(i) - 'A'; + alphabetMarker[alphabetIndex] = true; + } + } + for (boolean index : alphabetMarker) { + if (!index) + return false; + } + return true; + } + + public static boolean isPanagramWithStreams(String str) { + if (str == null) + return false; + + // filtered character stream + str = str.toUpperCase(); + Stream filteredCharStream = str.chars() + .filter(item -> ((item >= 'A' && item <= 'Z') || (item >= 'a' && item <= 'z'))) + .mapToObj(c -> (char) c); + Map alphabetMap = filteredCharStream.collect(Collectors.toMap(item -> item, k -> Boolean.TRUE, (p1, p2) -> p1)); + + return (alphabetMap.size() == 26); + } + + public static boolean isPerfectPanagram(String str) { + if (str == null) + return false; + + // filtered character stream + str = str.toUpperCase(); + Stream filteredCharStream = str.chars() + .filter(item -> ((item >= 'A' && item <= 'Z') || (item >= 'a' && item <= 'z'))) + .mapToObj(c -> (char) c); + Map alphabetFrequencyMap = filteredCharStream.collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + + return (alphabetFrequencyMap.size() == 26 && alphabetFrequencyMap.values() + .stream() + .allMatch(item -> item == 1)); + } +} From 725076b8ee4593c3dbccd6b5006edc657e0c0bbb Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Wed, 2 Jan 2019 22:18:53 +0400 Subject: [PATCH 046/139] performance tests tune up --- .../com/baeldung/performance/ArrayListBenchmark.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java index 1eeb17df87..331ae8d908 100644 --- a/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java +++ b/core-java-collections/src/main/java/com/baeldung/performance/ArrayListBenchmark.java @@ -9,7 +9,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) +@OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 10) public class ArrayListBenchmark { @@ -63,6 +63,7 @@ public class ArrayListBenchmark { public Employee testGet(ArrayListBenchmark.MyState state) { return state.employeeList.get(state.employeeIndex); } + @Benchmark public Employee testVectorGet(ArrayListBenchmark.MyState state) { return state.employeeVector.get(state.employeeIndex); @@ -78,14 +79,9 @@ public class ArrayListBenchmark { state.employeeList.add(new Employee(state.iterations + 1, "John")); } - @Benchmark - public void testAddVector(ArrayListBenchmark.MyState state) { - state.employeeVector.add(new Employee(state.iterations + 1, "John")); - } - public static void main(String[] args) throws Exception { Options options = new OptionsBuilder() - .include(ArrayListBenchmark.class.getSimpleName()).threads(1) + .include(ArrayListBenchmark.class.getSimpleName()).threads(3) .forks(1).shouldFailOnError(true) .shouldDoGC(true) .jvmArgs("-server").build(); From 9a8e006d73870b24c3116575ad56b97b319ab8ee Mon Sep 17 00:00:00 2001 From: Loredana Date: Wed, 2 Jan 2019 21:58:02 +0200 Subject: [PATCH 047/139] fix abstract factory ex --- .../creational/abstractfactory/AbstractFactory.java | 5 ++--- .../abstractfactory/AbstractPatternDriver.java | 4 ++-- .../creational/abstractfactory/AnimalFactory.java | 9 ++------- .../creational/abstractfactory/ColorFactory.java | 9 ++------- .../abstractfactory/AbstractPatternIntegrationTest.java | 4 ++-- 5 files changed, 10 insertions(+), 21 deletions(-) diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java index 5b4bf08006..88e819c066 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractFactory.java @@ -1,6 +1,5 @@ package com.baeldung.creational.abstractfactory; -public interface AbstractFactory { - Animal getAnimal(String toyType) ; - Color getColor(String colorType); +public interface AbstractFactory { + T create(String type) ; } \ No newline at end of file diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java index 68759d5aff..c1501091c5 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AbstractPatternDriver.java @@ -6,10 +6,10 @@ public class AbstractPatternDriver { //creating a brown toy dog abstractFactory = FactoryProvider.getFactory("Toy"); - Animal toy = abstractFactory.getAnimal("Dog"); + Animal toy =(Animal) abstractFactory.create("Dog"); abstractFactory = FactoryProvider.getFactory("Color"); - Color color = abstractFactory.getColor("Brown"); + Color color =(Color) abstractFactory.create("Brown"); String result = "A " + toy.getType() + " with " + color.getColor() + " color " + toy.makeSound(); diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java index bbc3eb7a82..4b46261571 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/AnimalFactory.java @@ -1,9 +1,9 @@ package com.baeldung.creational.abstractfactory; -public class AnimalFactory implements AbstractFactory { +public class AnimalFactory implements AbstractFactory { @Override - public Animal getAnimal(String animalType) { + public Animal create(String animalType) { if ("Dog".equalsIgnoreCase(animalType)) { return new Dog(); } else if ("Duck".equalsIgnoreCase(animalType)) { @@ -13,9 +13,4 @@ public class AnimalFactory implements AbstractFactory { return null; } - @Override - public Color getColor(String color) { - throw new UnsupportedOperationException(); - } - } diff --git a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java index 8b7e4f8086..3d9c5c18a3 100644 --- a/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java +++ b/patterns/design-patterns/src/main/java/com/baeldung/creational/abstractfactory/ColorFactory.java @@ -1,9 +1,9 @@ package com.baeldung.creational.abstractfactory; -public class ColorFactory implements AbstractFactory { +public class ColorFactory implements AbstractFactory { @Override - public Color getColor(String colorType) { + public Color create(String colorType) { if ("Brown".equalsIgnoreCase(colorType)) { return new Brown(); } else if ("White".equalsIgnoreCase(colorType)) { @@ -13,9 +13,4 @@ public class ColorFactory implements AbstractFactory { return null; } - @Override - public Animal getAnimal(String toyType) { - throw new UnsupportedOperationException(); - } - } diff --git a/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java b/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java index 6d1a4ad8fd..4f02249a4b 100644 --- a/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java +++ b/patterns/design-patterns/src/test/java/com/baeldung/creational/abstractfactory/AbstractPatternIntegrationTest.java @@ -11,10 +11,10 @@ public class AbstractPatternIntegrationTest { //creating a brown toy dog abstractFactory = FactoryProvider.getFactory("Toy"); - Animal toy = abstractFactory.getAnimal("Dog"); + Animal toy = (Animal) abstractFactory.create("Dog"); abstractFactory = FactoryProvider.getFactory("Color"); - Color color = abstractFactory.getColor("Brown"); + Color color =(Color) abstractFactory.create("Brown"); String result = "A " + toy.getType() + " with " + color.getColor() + " color " + toy.makeSound(); assertEquals("A Dog with brown color Barks", result); From e0a063a932aead8d7b664eed674672b5bea4387f Mon Sep 17 00:00:00 2001 From: DOHA Date: Wed, 2 Jan 2019 22:25:14 +0200 Subject: [PATCH 048/139] remove unused SecurityConfig --- .../com/baeldung/boot/SecurityConfig.java | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java diff --git a/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java b/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java deleted file mode 100644 index 61e86d01c5..0000000000 --- a/spring-boot-testing/src/main/java/com/baeldung/boot/SecurityConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -//package com.baeldung.boot; -// -//import org.springframework.context.annotation.Configuration; -//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -//import org.springframework.security.config.annotation.web.builders.HttpSecurity; -//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -// -// -//@Configuration -//@EnableWebSecurity -//public class SecurityConfig extends WebSecurityConfigurerAdapter { -// -// @Override -// protected void configure(AuthenticationManagerBuilder auth) throws Exception { -// auth.inMemoryAuthentication() -// .withUser("john") -// .password("{noop}123") -// .roles("USER"); -// } -// -// @Override -// protected void configure(HttpSecurity http) throws Exception { -// http.authorizeRequests() -// .antMatchers("/hello") -// .permitAll() -// .anyRequest() -// .authenticated() -// .and() -// .httpBasic(); -// } -//} \ No newline at end of file From 23de38295f0efe7c3f7767b4cee3ce92bd3ce43b Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:49:58 +0200 Subject: [PATCH 049/139] Update README.md --- core-java-8/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-8/README.md b/core-java-8/README.md index f9af585ab3..892dc71f76 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -37,3 +37,4 @@ - [Java @SuppressWarnings Annotation](https://www.baeldung.com/java-suppresswarnings) - [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) - [Java @Deprecated Annotation](https://www.baeldung.com/java-deprecated) +- [Java 8 Predicate Chain](https://www.baeldung.com/java-predicate-chain) From f912eaf5d98c8d51f444b9cca4ecd9523f89bf94 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:50:52 +0200 Subject: [PATCH 050/139] Update README.md --- core-java-lang/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-lang/README.md b/core-java-lang/README.md index 52dfe708a3..f7aa47008d 100644 --- a/core-java-lang/README.md +++ b/core-java-lang/README.md @@ -33,3 +33,4 @@ - [How to Separate Double into Integer and Decimal Parts](https://www.baeldung.com/java-separate-double-into-integer-decimal-parts) - [“Sneaky Throws” in Java](http://www.baeldung.com/java-sneaky-throws) - [Retrieving a Class Name in Java](https://www.baeldung.com/java-class-name) +- [Guide to Java Packages](https://www.baeldung.com/java-packages) From 53b0c016fff0863cc47342edb2c1892ef89bb9bf Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:53:09 +0200 Subject: [PATCH 051/139] Update README.md --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index 2b948a683a..e973907248 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -23,3 +23,4 @@ - [Difference Between @JoinColumn and mappedBy](https://www.baeldung.com/jpa-joincolumn-vs-mappedby) - [Hibernate 5 Bootstrapping API](https://www.baeldung.com/hibernate-5-bootstrapping-api) - [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel) +- [Guide to the Hibernate EntityManager](https://www.baeldung.com/hibernate-entitymanager) From 13e4081fc7a22111cfbf4c075dfd87eaab3471f1 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:53:54 +0200 Subject: [PATCH 052/139] Update README.md --- java-collections-maps/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/java-collections-maps/README.md b/java-collections-maps/README.md index a6037a3c57..0b76ca1959 100644 --- a/java-collections-maps/README.md +++ b/java-collections-maps/README.md @@ -17,3 +17,4 @@ - [Finding the Highest Value in a Java Map](https://www.baeldung.com/java-find-map-max) - [Merging Two Maps with Java 8](https://www.baeldung.com/java-merge-maps) - [How to Check If a Key Exists in a Map](https://www.baeldung.com/java-map-key-exists) +- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps) From 1a76da2f8f589204f57fc1d7a6e9b7bf45c37c72 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:54:36 +0200 Subject: [PATCH 053/139] Update README.md --- core-java-lang/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-lang/README.md b/core-java-lang/README.md index 52dfe708a3..d5ad7d8e7c 100644 --- a/core-java-lang/README.md +++ b/core-java-lang/README.md @@ -33,3 +33,4 @@ - [How to Separate Double into Integer and Decimal Parts](https://www.baeldung.com/java-separate-double-into-integer-decimal-parts) - [“Sneaky Throws” in Java](http://www.baeldung.com/java-sneaky-throws) - [Retrieving a Class Name in Java](https://www.baeldung.com/java-class-name) +- [Java Compound Operators](https://www.baeldung.com/java-compound-operators) From 7b666654ec11d8e4b524d3fc44be572f6101d8ed Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:56:06 +0200 Subject: [PATCH 054/139] Update README.md --- persistence-modules/java-jpa/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persistence-modules/java-jpa/README.md b/persistence-modules/java-jpa/README.md index 9a90216519..2eea5e60b4 100644 --- a/persistence-modules/java-jpa/README.md +++ b/persistence-modules/java-jpa/README.md @@ -2,4 +2,5 @@ - [A Guide to SqlResultSetMapping](http://www.baeldung.com/jpa-sql-resultset-mapping) - [A Guide to Stored Procedures with JPA](http://www.baeldung.com/jpa-stored-procedures) -- [Fixing the JPA error “java.lang.String cannot be cast to [Ljava.lang.String;”](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast) +- [Fixing the JPA error “java.lang.String cannot be cast to Ljava.lang.String;”](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast) +- [JPA Entity Graph](https://www.baeldung.com/jpa-entity-graph) From 6903a0c2bbdd72081fa8cac9f16d35f78bd05340 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 2 Jan 2019 22:56:48 +0200 Subject: [PATCH 055/139] Update README.md --- spring-5-security-oauth/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-5-security-oauth/README.md b/spring-5-security-oauth/README.md index f13925992b..5a444d4784 100644 --- a/spring-5-security-oauth/README.md +++ b/spring-5-security-oauth/README.md @@ -2,3 +2,4 @@ - [Spring Security 5 -OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login) - [Extracting Principal and Authorities using Spring Security OAuth](https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor) +- [Customizing Authorization and Token Requests with Spring Security 5.1 Client](https://www.baeldung.com/spring-security-custom-oauth-requests) From 2ec62d9091c005a8783f71a8af63076e18f12c73 Mon Sep 17 00:00:00 2001 From: DOHA Date: Wed, 2 Jan 2019 23:16:14 +0200 Subject: [PATCH 056/139] minor clean up --- spring-boot-testing/pom.xml | 44 +------------------ ...tionTest.groovy => LoadContextTest.groovy} | 2 +- ...onTest.groovy => WebControllerTest.groovy} | 2 +- 3 files changed, 3 insertions(+), 45 deletions(-) rename spring-boot-testing/src/test/groovy/com/baeldung/boot/{LoadContextIntegrationTest.groovy => LoadContextTest.groovy} (91%) rename spring-boot-testing/src/test/groovy/com/baeldung/boot/{WebControllerIntegrationTest.groovy => WebControllerTest.groovy} (97%) diff --git a/spring-boot-testing/pom.xml b/spring-boot-testing/pom.xml index dd40789604..c2c886a4fe 100644 --- a/spring-boot-testing/pom.xml +++ b/spring-boot-testing/pom.xml @@ -109,53 +109,11 @@ - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IntegrationTest.java - - - - + - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - - com.baeldung.boot.Application diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy similarity index 91% rename from spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy index 8bfc86685c..85b0a4b89b 100644 --- a/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextIntegrationTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/LoadContextTest.groovy @@ -10,7 +10,7 @@ import spock.lang.Title @Title("Application Specification") @Narrative("Specification which beans are expected") @SpringBootTest -class LoadContextIntegrationTest extends Specification { +class LoadContextTest extends Specification { @Autowired(required = false) private WebController webController diff --git a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy similarity index 97% rename from spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy rename to spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy index 17c60376ed..d8b4e03adc 100644 --- a/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerIntegrationTest.groovy +++ b/spring-boot-testing/src/test/groovy/com/baeldung/boot/WebControllerTest.groovy @@ -14,7 +14,7 @@ import spock.lang.Title @Narrative("The Specification of the behaviour of the WebController. It can greet a person, change the name and reset it to 'world'") @AutoConfigureMockMvc(secure=false) @WebMvcTest() -class WebControllerIntegrationTest extends Specification { +class WebControllerTest extends Specification { @Autowired private MockMvc mvc From bbb6c93598e4c401ee000392a69f96a8badaa4b6 Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Wed, 2 Jan 2019 22:13:35 -0200 Subject: [PATCH 057/139] [BAEL-2315] spring-5-reactive-oauth & spring-5-security-oauth | WebClient and OAuth2 support (#6053) * Cleaned shared properties in spring-5-security-oauth module, and made some final tunings on authorization service and the resource server * Added and modified example for webclient-oauth2 * Cleaned authorization service and resource service for webclient and oauth2 article * Added examples for auth code with client and with login cleaned properties and packages * Added examples fow webclient + oauth2 --- .../Spring5ReactiveOauthApplication.java | 2 + .../OauthClientApplication.java | 24 +++++++ .../configuration/WebClientConfig.java | 20 ++++++ .../configuration/WebSecurityConfig.java | 22 ++++++ .../web/ClientRestController.java | 53 +++++++++++++++ .../OauthClientApplication.java | 24 +++++++ .../configuration/WebClientConfig.java | 31 +++++++++ .../configuration/WebSecurityConfig.java | 20 ++++++ .../web/ClientRestController.java | 68 +++++++++++++++++++ .../ClientCredentialsOauthApplication.java | 26 +++++++ .../configuration/WebClientConfig.java | 22 ++++++ .../service/WebClientChonJob.java | 33 +++++++++ .../ManualRequestApplication.java | 23 +++++++ .../configure/WebClientConfig.java | 16 +++++ .../configure/WebSecurityConfig.java | 17 +++++ .../web/ManualOauthRequestController.java | 57 ++++++++++++++++ .../src/main/resources/application.yml | 23 +------ .../main/resources/default-application.yml | 20 ++++++ ...nt-auth-code-client-application.properties | 10 +++ ...ent-auth-code-login-application.properties | 10 +++ ...t-credentials-oauth-application.properties | 4 ++ .../OAuth2ClientCredentialsLiveTest.java | 52 ++++++++++++++ .../OAuth2ManualRequestLiveTest.java | 43 ++++++++++++ .../webclient/utils/ListAppender.java | 25 +++++++ .../src/test/resources/logback-test.xml | 16 +++++ .../oauth2/SpringOAuthApplication.java | 2 + .../ExtractorsApplication.java | 2 + .../AuthorizationServerApplication.java | 17 +++++ .../configuration/WebSecurityConfig.java | 26 +++++++ .../ResourceServerApplication.java | 17 +++++ .../configuration/AuthorizationConfigs.java | 29 ++++++++ .../web/ResourceRestController.java | 23 +++++++ .../src/main/resources/application.properties | 2 - .../resources/default-application.properties | 1 + ...lient-authorization-application.properties | 13 ++++ ...webclient-resources-application.properties | 6 ++ 36 files changed, 777 insertions(+), 22 deletions(-) create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java create mode 100644 spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java create mode 100644 spring-5-reactive-oauth/src/main/resources/default-application.yml create mode 100644 spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties create mode 100644 spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties create mode 100644 spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties create mode 100644 spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java create mode 100644 spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java create mode 100644 spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java create mode 100644 spring-5-reactive-oauth/src/test/resources/logback-test.xml create mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java create mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java create mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java create mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java create mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java create mode 100644 spring-5-security-oauth/src/main/resources/default-application.properties create mode 100644 spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties create mode 100644 spring-5-security-oauth/src/main/resources/webclient-resources-application.properties diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java index 602ded6b9e..b95517200e 100644 --- a/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/reactive/oauth/Spring5ReactiveOauthApplication.java @@ -3,11 +3,13 @@ package com.baeldung.reactive.oauth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; import org.springframework.web.reactive.function.client.WebClient; +@PropertySource("classpath:default-application.yml") @SpringBootApplication public class Spring5ReactiveOauthApplication { diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java new file mode 100644 index 0000000000..7bae78bb14 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.webclient.authorizationcodeclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-auth-code-client-application.properties") +@SpringBootApplication +public class OauthClientApplication { + + public static void main(String[] args) { + SpringApplication.run(OauthClientApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java new file mode 100644 index 0000000000..884a3c145d --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebClientConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.webclient.authorizationcodeclient.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + return WebClient.builder() + .filter(oauth) + .build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..4271ae96cf --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/configuration/WebSecurityConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.webclient.authorizationcodeclient.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .authenticated() + .and() + .oauth2Client() + .and() + .formLogin(); + return http.build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java new file mode 100644 index 0000000000..c36b7d1dea --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/web/ClientRestController.java @@ -0,0 +1,53 @@ +package com.baeldung.webclient.authorizationcodeclient.web; + +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +@RestController +public class ClientRestController { + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + WebClient webClient; + + @GetMapping("/auth-code") + Mono useOauthWithAuthCode() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-annotated") + Mono useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .attributes(oauth2AuthorizedClient(authorizedClient)) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken() + .getExpiresAt()); + } + + @GetMapping("/auth-code-explicit-client") + Mono useOauthWithExpicitClient() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .attributes(clientRegistrationId("bael")) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java new file mode 100644 index 0000000000..9dd6dd1bde --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.webclient.authorizationcodelogin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-auth-code-login-application.properties") +@SpringBootApplication +public class OauthClientApplication { + + public static void main(String[] args) { + SpringApplication.run(OauthClientApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java new file mode 100644 index 0000000000..15458cc60a --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebClientConfig.java @@ -0,0 +1,31 @@ +package com.baeldung.webclient.authorizationcodelogin.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + @Primary + WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + oauth.setDefaultOAuth2AuthorizedClient(true); + return WebClient.builder() + .filter(oauth) + .build(); + } + + @Bean + WebClient otherWebClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients); + return WebClient.builder() + .filter(oauth) + .build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..f45fc09222 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/configuration/WebSecurityConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.webclient.authorizationcodelogin.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .authenticated() + .and() + .oauth2Login(); + return http.build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java new file mode 100644 index 0000000000..55e0096525 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/web/ClientRestController.java @@ -0,0 +1,68 @@ +package com.baeldung.webclient.authorizationcodelogin.web; + +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; +import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +@RestController +public class ClientRestController { + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + WebClient webClient; + + @Autowired + @Qualifier("otherWebClient") + WebClient otherWebClient; + + @GetMapping("/auth-code") + Mono useOauthWithAuthCode() { + Mono retrievedResource = webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-no-client") + Mono useOauthWithNoClient() { + // This call will fail, since we don't have the client properly set for this webClient + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + + @GetMapping("/auth-code-annotated") + Mono useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) { + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .attributes(oauth2AuthorizedClient(authorizedClient)) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken() + .getExpiresAt()); + } + + @GetMapping("/auth-code-explicit-client") + Mono useOauthWithExpicitClient() { + Mono retrievedResource = otherWebClient.get() + .uri(RESOURCE_URI) + .attributes(clientRegistrationId("bael")) + .retrieve() + .bodyToMono(String.class); + return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java new file mode 100644 index 0000000000..d1b9f7f744 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/ClientCredentialsOauthApplication.java @@ -0,0 +1,26 @@ +package com.baeldung.webclient.clientcredentials; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using credentials handled by the auth server (bael-user/bael-password) + * + * @author rozagerardo + * + */ +@PropertySource("classpath:webclient-client-credentials-oauth-application.properties") +@EnableScheduling +@SpringBootApplication +public class ClientCredentialsOauthApplication { + + public static void main(String[] args) { + SpringApplication.run(ClientCredentialsOauthApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java new file mode 100644 index 0000000000..8ffc92b4cd --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/configuration/WebClientConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.webclient.clientcredentials.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) { + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository()); + oauth.setDefaultClientRegistrationId("bael"); + return WebClient.builder() + .filter(oauth) + .build(); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java new file mode 100644 index 0000000000..dc38ce3f9e --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/clientcredentials/service/WebClientChonJob.java @@ -0,0 +1,33 @@ +package com.baeldung.webclient.clientcredentials.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +@Component +public class WebClientChonJob { + + Logger logger = LoggerFactory.getLogger(WebClientChonJob.class); + + private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + + @Autowired + private WebClient webClient; + + @Scheduled(fixedRate = 1000) + public void logResourceServiceResponse() { + + webClient.get() + .uri(RESOURCE_URI) + .retrieve() + .bodyToMono(String.class) + .map(string -> "We retrieved the following resource using Client Credentials Grant Type: " + string) + .subscribe(logger::info); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java new file mode 100644 index 0000000000..c2762ad559 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/ManualRequestApplication.java @@ -0,0 +1,23 @@ +package com.baeldung.webclient.manualrequest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +/** + * + * Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth + * + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server + * + * @author rozagerardo + * + */ +@SpringBootApplication +public class ManualRequestApplication { + + public static void main(String[] args) { + SpringApplication.run(ManualRequestApplication.class, args); + } + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java new file mode 100644 index 0000000000..51fc60821a --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebClientConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.webclient.manualrequest.configure; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + public WebClient configureWebClient() { + return WebClient.builder() + .build(); + }; + +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java new file mode 100644 index 0000000000..1753681db8 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/configure/WebSecurityConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.manualrequest.configure; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +public class WebSecurityConfig { + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange() + .anyExchange() + .permitAll(); + return http.build(); + } +} diff --git a/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java new file mode 100644 index 0000000000..9f9d6d3167 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/manualrequest/web/ManualOauthRequestController.java @@ -0,0 +1,57 @@ +package com.baeldung.webclient.manualrequest.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.util.Base64Utils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; + +import com.fasterxml.jackson.databind.JsonNode; +import com.nimbusds.oauth2.sdk.GrantType; + +import reactor.core.publisher.Mono; + +@RestController +public class ManualOauthRequestController { + + private static Logger logger = LoggerFactory.getLogger(ManualOauthRequestController.class); + + private static final String TOKEN_ENDPOINT = "localhost:8085/oauth/token"; + private static final String RESOURCE_ENDPOINT = "localhost:8084/retrieve-resource"; + private static final String CLIENT_ID = "bael-client-id"; + private static final String CLIENT_SECRET = "bael-secret"; + + @Autowired + WebClient client; + + @GetMapping("/manual-request-oauth") + public Mono obtainSecuredResource() { + logger.info("Creating web client..."); + Mono resource = client.post() + .uri(TOKEN_ENDPOINT) + .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes())) + .body(BodyInserters.fromFormData(OAuth2ParameterNames.GRANT_TYPE, GrantType.CLIENT_CREDENTIALS.getValue())) + .retrieve() + .bodyToMono(JsonNode.class) + .flatMap(tokenResponse -> { + String accessTokenValue = tokenResponse.get("access_token") + .textValue(); + logger.info("Retrieved the following access token: {}", accessTokenValue); + return client.get() + .uri(RESOURCE_ENDPOINT) + .headers(h -> h.setBearerAuth(accessTokenValue)) + .retrieve() + .bodyToMono(String.class); + }); + logger.info("non-blocking Oauth calls registered..."); + return resource.map(res -> "Retrieved the resource using a manual approach: " + res); + + } + +} diff --git a/spring-5-reactive-oauth/src/main/resources/application.yml b/spring-5-reactive-oauth/src/main/resources/application.yml index e35e19b344..bec62fdd33 100644 --- a/spring-5-reactive-oauth/src/main/resources/application.yml +++ b/spring-5-reactive-oauth/src/main/resources/application.yml @@ -1,20 +1,3 @@ -spring: - security: - oauth2: - client: - registration: - google: - client-id: YOUR_APP_CLIENT_ID - client-secret: YOUR_APP_CLIENT_SECRET - custom: - client-id: fooClientIdPassword - client-secret: secret - scopes: read,foo - authorization-grant-type: authorization_code - redirect-uri-template: http://localhost:8080/login/oauth2/code/custom - provider: - custom: - authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize - token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token - user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra - user-name-attribute: user_name \ No newline at end of file +logging: + level: + root: DEBUG \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/main/resources/default-application.yml b/spring-5-reactive-oauth/src/main/resources/default-application.yml new file mode 100644 index 0000000000..e35e19b344 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/default-application.yml @@ -0,0 +1,20 @@ +spring: + security: + oauth2: + client: + registration: + google: + client-id: YOUR_APP_CLIENT_ID + client-secret: YOUR_APP_CLIENT_SECRET + custom: + client-id: fooClientIdPassword + client-secret: secret + scopes: read,foo + authorization-grant-type: authorization_code + redirect-uri-template: http://localhost:8080/login/oauth2/code/custom + provider: + custom: + authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize + token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token + user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra + user-name-attribute: user_name \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties new file mode 100644 index 0000000000..612777a06d --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-client-application.properties @@ -0,0 +1,10 @@ +spring.security.oauth2.client.registration.bael.client-name=bael +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/authorize/oauth2/code/bael + +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize + +spring.security.user.password=pass diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties new file mode 100644 index 0000000000..edd5b80b13 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-auth-code-login-application.properties @@ -0,0 +1,10 @@ +spring.security.oauth2.client.registration.bael.client-name=bael +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code +spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/login/oauth2/code/bael + +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize +spring.security.oauth2.client.provider.bael.user-info-uri=http://localhost:8084/user +spring.security.oauth2.client.provider.bael.user-name-attribute=name diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties new file mode 100644 index 0000000000..f82f74ec48 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-client-credentials-oauth-application.properties @@ -0,0 +1,4 @@ +spring.security.oauth2.client.registration.bael.authorization-grant-type=client_credentials +spring.security.oauth2.client.registration.bael.client-id=bael-client-id +spring.security.oauth2.client.registration.bael.client-secret=bael-secret +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java new file mode 100644 index 0000000000..e31815c3f8 --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/clientcredentials/OAuth2ClientCredentialsLiveTest.java @@ -0,0 +1,52 @@ +package com.baeldung.webclient.clientcredentials; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.stream.Collectors; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.webclient.clientcredentials.service.WebClientChonJob; +import com.baeldung.webclient.utils.ListAppender; + +import ch.qos.logback.classic.spi.ILoggingEvent; + +/** + * + * Note: this Live test requires the Authorization Service and the Resource service located in the spring-5-security-oauth module + * + * @author ger + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { ClientCredentialsOauthApplication.class }) +public class OAuth2ClientCredentialsLiveTest { + + @Autowired + WebClientChonJob service; + + @Before + public void clearLogList() { + ListAppender.clearEventList(); + } + + @Test + public void givenFooWithNullId_whenProcessFoo_thenLogsWithDebugTrace() throws Exception { + service.logResourceServiceResponse(); + + Thread.sleep(3000); + + Collection allLoggedEntries = ListAppender.getEvents() + .stream() + .map(ILoggingEvent::getFormattedMessage) + .collect(Collectors.toList()); + assertThat(allLoggedEntries).anyMatch(entry -> entry.contains("We retrieved the following resource using Client Credentials Grant Type: This is the resource!")); + } + +} diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java new file mode 100644 index 0000000000..94aa580f0a --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/manualrequest/OAuth2ManualRequestLiveTest.java @@ -0,0 +1,43 @@ +package com.baeldung.webclient.manualrequest; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; + +/** + * + * Note: this Live test requires not only the corresponding application running, + * but also the Authorization Service and the Resource service located in the spring-5-security-oauth module. + * + * + * @author ger + * + */ +public class OAuth2ManualRequestLiveTest { + + private static final String BASE_URL = "http://localhost:8080"; + private static final String MANUAL_REQUEST_URI = "/manual-request-oauth"; + + private static WebTestClient client; + + @Before + public void setup() { + client = WebTestClient.bindToServer() + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void whenRequestingDebugHookOn_thenObtainExpectedMessage() { + ResponseSpec response = client.get() + .uri(MANUAL_REQUEST_URI) + .exchange(); + + response.expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Retrieved the resource using a manual approach: This is the resource!"); + } + +} diff --git a/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java new file mode 100644 index 0000000000..6f8fbe004a --- /dev/null +++ b/spring-5-reactive-oauth/src/test/java/com/baeldung/webclient/utils/ListAppender.java @@ -0,0 +1,25 @@ +package com.baeldung.webclient.utils; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +public class ListAppender extends AppenderBase { + + static private List events = new ArrayList<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + events.add(eventObject); + } + + public static List getEvents() { + return events; + } + + public static void clearEventList() { + events.clear(); + } +} \ No newline at end of file diff --git a/spring-5-reactive-oauth/src/test/resources/logback-test.xml b/spring-5-reactive-oauth/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..891c54bfd3 --- /dev/null +++ b/spring-5-reactive-oauth/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java index 557c23b368..1478b03d2e 100644 --- a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java +++ b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2/SpringOAuthApplication.java @@ -2,7 +2,9 @@ package com.baeldung.oauth2; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +@PropertySource("classpath:default-application.properties") @SpringBootApplication public class SpringOAuthApplication { diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java index 6ab4d525bf..174e5b0fdf 100644 --- a/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java +++ b/spring-5-security-oauth/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java @@ -3,10 +3,12 @@ package com.baeldung.oauth2extractors; import org.apache.logging.log4j.util.Strings; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.AbstractEnvironment; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +@PropertySource("classpath:default-application.properties") @SpringBootApplication @Controller public class ExtractorsApplication { diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java new file mode 100644 index 0000000000..d72704386c --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.authorizationserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; + +@EnableAuthorizationServer +@PropertySource("classpath:webclient-authorization-application.properties") +@SpringBootApplication +public class AuthorizationServerApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthorizationServerApplication.class, args); + } + +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java new file mode 100644 index 0000000000..5dd15f1b8c --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java @@ -0,0 +1,26 @@ +package com.baeldung.webclient.authorizationserver.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/login", "/user") + .permitAll() + .and() + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .httpBasic(); + } +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java new file mode 100644 index 0000000000..50ad293ef8 --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.webclient.resourceserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; + +@EnableResourceServer +@PropertySource("webclient-resources-application.properties") +@SpringBootApplication +public class ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ResourceServerApplication.class, args); + } + +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java new file mode 100644 index 0000000000..5aea1983db --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java @@ -0,0 +1,29 @@ +package com.baeldung.webclient.resourceserver.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.RemoteTokenServices; +import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; + +@Configuration +public class AuthorizationConfigs { + + @Value("${oauth.authserver.client-id}") + String clientId; + + @Value("${oauth.authserver.client-secret}") + String clientSecret; + + @Value("${oauth.authserver.check-token-endpoint}") + String checkTokenEndpoint; + + @Bean + public ResourceServerTokenServices tokenSvc() { + RemoteTokenServices remoteService = new RemoteTokenServices(); + remoteService.setCheckTokenEndpointUrl(checkTokenEndpoint); + remoteService.setClientId(clientId); + remoteService.setClientSecret(clientSecret); + return remoteService; + } +} diff --git a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java new file mode 100644 index 0000000000..aef0fb4d7d --- /dev/null +++ b/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java @@ -0,0 +1,23 @@ +package com.baeldung.webclient.resourceserver.web; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ResourceRestController { + + @GetMapping("/retrieve-resource") + public String retrieveResource() { + return "This is the resource!"; + } + + @GetMapping("/user") + @ResponseBody + public Principal user(Principal user) { + return user; + } + +} diff --git a/spring-5-security-oauth/src/main/resources/application.properties b/spring-5-security-oauth/src/main/resources/application.properties index 5912b0f755..c84e745918 100644 --- a/spring-5-security-oauth/src/main/resources/application.properties +++ b/spring-5-security-oauth/src/main/resources/application.properties @@ -1,5 +1,3 @@ -server.port=8081 - logging.level.root=INFO logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/default-application.properties b/spring-5-security-oauth/src/main/resources/default-application.properties new file mode 100644 index 0000000000..bafddced85 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/default-application.properties @@ -0,0 +1 @@ +server.port=8081 \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties b/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties new file mode 100644 index 0000000000..9531045359 --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties @@ -0,0 +1,13 @@ +server.port=8085 + +security.oauth2.client.client-id=bael-client-id +security.oauth2.client.client-secret=bael-secret +security.oauth2.client.scope=read,write + +security.oauth2.authorization.check-token-access=isAuthenticated() + +spring.security.user.name=bael-user +spring.security.user.password=bael-password + +security.oauth2.client.registered-redirect-uri=http://localhost:8080/login/oauth2/code/bael, http://localhost:8080/authorize/oauth2/code/bael +security.oauth2.client.use-current-uri=false \ No newline at end of file diff --git a/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties b/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties new file mode 100644 index 0000000000..1cfb9ca12d --- /dev/null +++ b/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties @@ -0,0 +1,6 @@ +server.port=8084 + +#spring.security.oauth2.resourceserver.jwt.issuer-uri=localhost:8085 +oauth.authserver.client-id=bael-client-id +oauth.authserver.client-secret=bael-secret +oauth.authserver.check-token-endpoint=http://localhost:8085/oauth/check_token From eacc84a450dad6e85354ea7e3acf72e902dcae19 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Thu, 3 Jan 2019 08:08:25 +0530 Subject: [PATCH 058/139] BAEL-2536-added-unit-tests-for-panagram --- .../com/baeldung/string/PanagramUnitTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java diff --git a/java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java new file mode 100644 index 0000000000..81d46956e2 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.string; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + + +public class PanagramUnitTest { + + @Test + public void givenValidString_isPanagram_shouldReturnSuccess() { + String input = "Two driven jocks help fax my big quiz"; + assertTrue(Panagram.isPanagram(input)); + assertTrue(Panagram.isPanagramWithStreams(input)); + } + + @Test + public void givenNullString_isPanagram_shouldReturnFailure() { + String input = null; + assertFalse(Panagram.isPanagram(input)); + assertFalse(Panagram.isPanagramWithStreams(input)); + assertFalse(Panagram.isPerfectPanagram(input)); + } + + @Test + public void givenPerfectPanagramString_isPerfectPanagram_shouldReturnSuccess() { + String input = "abcdefghijklmNoPqrStuVwxyz"; + assertTrue(Panagram.isPerfectPanagram(input)); + } + + @Test + public void givenNonPanagramString_isPanagram_shouldReturnFailure() { + String input = "invalid panagram"; + assertFalse(Panagram.isPanagram(input)); + assertFalse(Panagram.isPanagramWithStreams(input)); + } + + @Test + public void givenPanagram_isPerfectPanagram_shouldReturnFailure() { + String input = "Two driven jocks help fax my big quiz"; + assertFalse(Panagram.isPerfectPanagram(input)); + } + +} From 34b90a33aac7df4feae5867355d72bb54ed4a045 Mon Sep 17 00:00:00 2001 From: Krzysztof Majewski Date: Thu, 3 Jan 2019 14:15:43 +0100 Subject: [PATCH 059/139] BAEL-2483 --- .../java/com/baeldung/annotation/MyBean.java | 26 +++++++++++++++++++ .../com/baeldung/annotation/TestBean.java | 8 ++++++ 2 files changed, 34 insertions(+) create mode 100644 spring-core/src/main/java/com/baeldung/annotation/MyBean.java create mode 100644 spring-core/src/main/java/com/baeldung/annotation/TestBean.java diff --git a/spring-core/src/main/java/com/baeldung/annotation/MyBean.java b/spring-core/src/main/java/com/baeldung/annotation/MyBean.java new file mode 100644 index 0000000000..9a1fd3beec --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/annotation/MyBean.java @@ -0,0 +1,26 @@ +package com.baeldung.annotation; + +import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@Component +public class MyBean { + + private final TestBean testBean; + + public MyBean(TestBean testBean) { + this.testBean = testBean; + System.out.println("Hello from constructor"); + } + + @PostConstruct + private void postConstruct() { + System.out.println("Hello from @PostConstruct method"); + } + + @PreDestroy + public void preDestroy() { + System.out.println("Bean is being destroyed"); + } +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/annotation/TestBean.java b/spring-core/src/main/java/com/baeldung/annotation/TestBean.java new file mode 100644 index 0000000000..0539e10751 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/annotation/TestBean.java @@ -0,0 +1,8 @@ +package com.baeldung.annotation; + +import org.springframework.stereotype.Component; + +@Component +public class TestBean { + +} \ No newline at end of file From bdcc961542282c5411d2ad7e6196dccccb9e075f Mon Sep 17 00:00:00 2001 From: ramansahasi Date: Thu, 3 Jan 2019 20:19:51 +0530 Subject: [PATCH 060/139] BAEL-2392_Java_String_interview_questions second commit (#6064) --- .../string/interview/LocaleUnitTest.java | 19 +++++++++++ .../interview/StringAnagramUnitTest.java | 29 +++++++++++++++++ .../interview/StringChangeCaseUnitTest.java | 20 ++++++++++++ .../StringCountOccurrencesUnitTest.java | 28 ++++++++++++++++ .../interview/StringFormatUnitTest.java | 14 ++++++++ .../interview/StringInternUnitTest.java | 17 ++++++++++ .../interview/StringJoinerUnitTest.java | 18 +++++++++++ .../interview/StringPalindromeUnitTest.java | 29 +++++++++++++++++ .../interview/StringReverseUnitTest.java | 13 ++++++++ .../string/interview/StringSplitUnitTest.java | 32 +++++++++++++++++++ .../interview/StringToByteArrayUnitTest.java | 24 ++++++++++++++ .../interview/StringToCharArrayUnitTest.java | 17 ++++++++++ .../interview/StringToIntegerUnitTest.java | 15 +++++++++ 13 files changed, 275 insertions(+) create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java diff --git a/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java new file mode 100644 index 0000000000..1d221056fd --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/LocaleUnitTest.java @@ -0,0 +1,19 @@ +package com.baeldung.string.interview; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.Locale; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class LocaleUnitTest { + @Test + public void whenUsingLocal_thenCorrectResultsForDifferentLocale() { + Locale usLocale = Locale.US; + BigDecimal number = new BigDecimal(102_300.456d); + + NumberFormat usNumberFormat = NumberFormat.getCurrencyInstance(usLocale); + assertEquals(usNumberFormat.format(number), "$102,300.46"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java new file mode 100644 index 0000000000..aadfade737 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringAnagramUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +import org.junit.Test; + +public class StringAnagramUnitTest { + public boolean isAnagram(String s1, String s2) { + if(s1.length() != s2.length()) + return false; + + char[] arr1 = s1.toCharArray(); + char[] arr2 = s2.toCharArray(); + + Arrays.sort(arr1); + Arrays.sort(arr2); + + return Arrays.equals(arr1, arr2); + } + + @Test + public void whenTestAnagrams_thenTestingCorrectly() { + assertThat(isAnagram("car", "arc")).isTrue(); + assertThat(isAnagram("west", "stew")).isTrue(); + assertThat(isAnagram("west", "east")).isFalse(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java new file mode 100644 index 0000000000..2c7ec500fe --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringChangeCaseUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringChangeCaseUnitTest { + @Test + public void givenString_whenChangingToUppercase_thenCaseChanged() { + String s = "Welcome to Baeldung!"; + assertEquals("WELCOME TO BAELDUNG!", s.toUpperCase()); + } + + + @Test + public void givenString_whenChangingToLowerrcase_thenCaseChanged() { + String s = "Welcome to Baeldung!"; + assertEquals("welcome to baeldung!", s.toLowerCase()); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java new file mode 100644 index 0000000000..6c17643ac8 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringCountOccurrencesUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringCountOccurrencesUnitTest { + public int countOccurrences(String s, char c) { + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == c) { + count++; + } + } + return count; + } + + @Test + public void givenString_whenCountingFrequencyOfChar_thenCountCorrect() { + assertEquals(3, countOccurrences("united states", 't')); + } + + public void givenString_whenUsingJava8_thenCountingOfCharCorrect() { + String str = "united states"; + long count = str.chars().filter(ch -> (char)ch == 't').count(); + assertEquals(3, count); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java new file mode 100644 index 0000000000..787017791c --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringFormatUnitTest.java @@ -0,0 +1,14 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringFormatUnitTest { + @Test + public void givenString_whenUsingStringFormat_thenStringFormatted() { + String title = "Baeldung"; + String formatted = String.format("Title is %s", title); + assertEquals(formatted, "Title is Baeldung"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java new file mode 100644 index 0000000000..c5bffb7573 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringInternUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class StringInternUnitTest { + @Test + public void whenCallingStringIntern_thenStringsInterned() { + String s1 = "Baeldung"; + String s2 = new String("Baeldung"); + String s3 = new String("Baeldung").intern(); + + assertThat(s1 == s2).isFalse(); + assertThat(s1 == s3).isTrue(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java new file mode 100644 index 0000000000..d44c7478e4 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringJoinerUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.string.interview; + +import java.util.StringJoiner; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringJoinerUnitTest { + @Test + public void whenUsingStringJoiner_thenStringsJoined() { + StringJoiner joiner = new StringJoiner(",", "[", "]"); + joiner.add("Red") + .add("Green") + .add("Blue"); + + assertEquals(joiner.toString(), "[Red,Green,Blue]"); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java new file mode 100644 index 0000000000..79ed14cd99 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringPalindromeUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.string.interview; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class StringPalindromeUnitTest { + + public boolean isPalindrome(String text) { + int forward = 0; + int backward = text.length() - 1; + while (backward > forward) { + char forwardChar = text.charAt(forward++); + char backwardChar = text.charAt(backward--); + if (forwardChar != backwardChar) + return false; + } + return true; + } + + @Test + public void givenIsPalindromeMethod_whenCheckingString_thenFindIfPalindrome() { + assertThat(isPalindrome("madam")).isTrue(); + assertThat(isPalindrome("radar")).isTrue(); + assertThat(isPalindrome("level")).isTrue(); + + assertThat(isPalindrome("baeldung")).isFalse(); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java new file mode 100644 index 0000000000..bb9b45dc97 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringReverseUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class StringReverseUnitTest { + @Test + public void whenUsingInbuildMethods_thenStringReversed() { + String reversed = new StringBuilder("baeldung").reverse().toString(); + assertEquals("gnudleab", reversed); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java new file mode 100644 index 0000000000..e1cea62462 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringSplitUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.string.interview; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; + +public class StringSplitUnitTest { + @Test + public void givenCoreJava_whenSplittingStrings_thenSplitted() { + String expected[] = { + "john", + "peter", + "mary" + }; + + String[] splitted = "john,peter,mary".split(","); + assertArrayEquals( expected, splitted ); + } + + @Test + public void givenApacheCommons_whenSplittingStrings_thenSplitted() { + String expected[] = { + "john", + "peter", + "mary" + }; + String[] splitted = StringUtils.split("john peter mary"); + assertArrayEquals( expected, splitted ); + } + + +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java new file mode 100644 index 0000000000..aee4eedcd6 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToByteArrayUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertArrayEquals; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +import org.junit.Test; + +public class StringToByteArrayUnitTest { + @Test + public void whenGetBytes_thenCorrect() throws UnsupportedEncodingException { + byte[] byteArray1 = "abcd".getBytes(); + byte[] byteArray2 = "efgh".getBytes(StandardCharsets.US_ASCII); + byte[] byteArray3 = "ijkl".getBytes("UTF-8"); + byte[] expected1 = new byte[] { 97, 98, 99, 100 }; + byte[] expected2 = new byte[] { 101, 102, 103, 104 }; + byte[] expected3 = new byte[] { 105, 106, 107, 108 }; + + assertArrayEquals(expected1, byteArray1); + assertArrayEquals(expected2, byteArray2); + assertArrayEquals(expected3, byteArray3); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java new file mode 100644 index 0000000000..1322d0fa82 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToCharArrayUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.string.interview; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class StringToCharArrayUnitTest { + @Test + public void whenConvertingStringToCharArray_thenConversionSuccessful() { + String beforeConvStr = "hello"; + char[] afterConvCharArr = { 'h', 'e', 'l', 'l', 'o' }; + + assertEquals(Arrays.equals(beforeConvStr.toCharArray(), afterConvCharArr), true); + } +} diff --git a/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java b/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java new file mode 100644 index 0000000000..a905438a84 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/interview/StringToIntegerUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.string.interview; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class StringToIntegerUnitTest { + @Test + public void givenString_whenParsingInt_shouldConvertToInt() { + String givenString = "42"; + + int result = Integer.parseInt(givenString); + + assertThat(result).isEqualTo(42); + } +} From 4eb3f2943038f3b0635e8267b7e9a666af6281d9 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Thu, 3 Jan 2019 22:42:26 +0530 Subject: [PATCH 061/139] BAEL-2536-addressed review comments --- .../string/{Panagram.java => Pangram.java} | 21 ++++++++++--------- ...gramUnitTest.java => PangramUnitTest.java} | 20 +++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) rename java-strings/src/main/java/com/baeldung/string/{Panagram.java => Pangram.java} (71%) rename java-strings/src/test/java/com/baeldung/string/{PanagramUnitTest.java => PangramUnitTest.java} (61%) diff --git a/java-strings/src/main/java/com/baeldung/string/Panagram.java b/java-strings/src/main/java/com/baeldung/string/Pangram.java similarity index 71% rename from java-strings/src/main/java/com/baeldung/string/Panagram.java rename to java-strings/src/main/java/com/baeldung/string/Pangram.java index d000b4455e..48e31b2157 100644 --- a/java-strings/src/main/java/com/baeldung/string/Panagram.java +++ b/java-strings/src/main/java/com/baeldung/string/Pangram.java @@ -6,12 +6,13 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -public class Panagram { +public class Pangram { + private static final int ALPHABET_COUNT = 26; public static boolean isPanagram(String str) { if (str == null) return false; - Boolean[] alphabetMarker = new Boolean[26]; + Boolean[] alphabetMarker = new Boolean[ALPHABET_COUNT]; Arrays.fill(alphabetMarker, false); int alphabetIndex = 0; str = str.toUpperCase(); @@ -33,13 +34,13 @@ public class Panagram { return false; // filtered character stream - str = str.toUpperCase(); - Stream filteredCharStream = str.chars() - .filter(item -> ((item >= 'A' && item <= 'Z') || (item >= 'a' && item <= 'z'))) + String strUpper = str.toUpperCase(); + Stream filteredCharStream = strUpper.chars() + .filter(item -> ((item >= 'A' && item <= 'Z'))) .mapToObj(c -> (char) c); Map alphabetMap = filteredCharStream.collect(Collectors.toMap(item -> item, k -> Boolean.TRUE, (p1, p2) -> p1)); - return (alphabetMap.size() == 26); + return (alphabetMap.size() == ALPHABET_COUNT); } public static boolean isPerfectPanagram(String str) { @@ -47,13 +48,13 @@ public class Panagram { return false; // filtered character stream - str = str.toUpperCase(); - Stream filteredCharStream = str.chars() - .filter(item -> ((item >= 'A' && item <= 'Z') || (item >= 'a' && item <= 'z'))) + String strUpper = str.toUpperCase(); + Stream filteredCharStream = strUpper.chars() + .filter(item -> ((item >= 'A' && item <= 'Z'))) .mapToObj(c -> (char) c); Map alphabetFrequencyMap = filteredCharStream.collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); - return (alphabetFrequencyMap.size() == 26 && alphabetFrequencyMap.values() + return (alphabetFrequencyMap.size() == ALPHABET_COUNT && alphabetFrequencyMap.values() .stream() .allMatch(item -> item == 1)); } diff --git a/java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java similarity index 61% rename from java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java rename to java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java index 81d46956e2..150f27d7c0 100644 --- a/java-strings/src/test/java/com/baeldung/string/PanagramUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java @@ -5,40 +5,40 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; -public class PanagramUnitTest { +public class PangramUnitTest { @Test public void givenValidString_isPanagram_shouldReturnSuccess() { String input = "Two driven jocks help fax my big quiz"; - assertTrue(Panagram.isPanagram(input)); - assertTrue(Panagram.isPanagramWithStreams(input)); + assertTrue(Pangram.isPanagram(input)); + assertTrue(Pangram.isPanagramWithStreams(input)); } @Test public void givenNullString_isPanagram_shouldReturnFailure() { String input = null; - assertFalse(Panagram.isPanagram(input)); - assertFalse(Panagram.isPanagramWithStreams(input)); - assertFalse(Panagram.isPerfectPanagram(input)); + assertFalse(Pangram.isPanagram(input)); + assertFalse(Pangram.isPanagramWithStreams(input)); + assertFalse(Pangram.isPerfectPanagram(input)); } @Test public void givenPerfectPanagramString_isPerfectPanagram_shouldReturnSuccess() { String input = "abcdefghijklmNoPqrStuVwxyz"; - assertTrue(Panagram.isPerfectPanagram(input)); + assertTrue(Pangram.isPerfectPanagram(input)); } @Test public void givenNonPanagramString_isPanagram_shouldReturnFailure() { String input = "invalid panagram"; - assertFalse(Panagram.isPanagram(input)); - assertFalse(Panagram.isPanagramWithStreams(input)); + assertFalse(Pangram.isPanagram(input)); + assertFalse(Pangram.isPanagramWithStreams(input)); } @Test public void givenPanagram_isPerfectPanagram_shouldReturnFailure() { String input = "Two driven jocks help fax my big quiz"; - assertFalse(Panagram.isPerfectPanagram(input)); + assertFalse(Pangram.isPerfectPanagram(input)); } } From 693da95f44bdd66609acc103824ad49b38f91141 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Thu, 3 Jan 2019 22:44:52 +0530 Subject: [PATCH 062/139] BAEL-2536-updated Panagram to Pangram --- .../main/java/com/baeldung/string/Pangram.java | 10 +++++----- .../com/baeldung/string/PangramUnitTest.java | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/java-strings/src/main/java/com/baeldung/string/Pangram.java b/java-strings/src/main/java/com/baeldung/string/Pangram.java index 48e31b2157..8498a7074a 100644 --- a/java-strings/src/main/java/com/baeldung/string/Pangram.java +++ b/java-strings/src/main/java/com/baeldung/string/Pangram.java @@ -9,7 +9,7 @@ import java.util.stream.Stream; public class Pangram { private static final int ALPHABET_COUNT = 26; - public static boolean isPanagram(String str) { + public static boolean isPangram(String str) { if (str == null) return false; Boolean[] alphabetMarker = new Boolean[ALPHABET_COUNT]; @@ -29,10 +29,10 @@ public class Pangram { return true; } - public static boolean isPanagramWithStreams(String str) { + public static boolean isPangramWithStreams(String str) { if (str == null) return false; - + // filtered character stream String strUpper = str.toUpperCase(); Stream filteredCharStream = strUpper.chars() @@ -43,10 +43,10 @@ public class Pangram { return (alphabetMap.size() == ALPHABET_COUNT); } - public static boolean isPerfectPanagram(String str) { + public static boolean isPerfectPangram(String str) { if (str == null) return false; - + // filtered character stream String strUpper = str.toUpperCase(); Stream filteredCharStream = strUpper.chars() diff --git a/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java index 150f27d7c0..67523a4524 100644 --- a/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java @@ -10,35 +10,35 @@ public class PangramUnitTest { @Test public void givenValidString_isPanagram_shouldReturnSuccess() { String input = "Two driven jocks help fax my big quiz"; - assertTrue(Pangram.isPanagram(input)); - assertTrue(Pangram.isPanagramWithStreams(input)); + assertTrue(Pangram.isPangram(input)); + assertTrue(Pangram.isPangramWithStreams(input)); } @Test public void givenNullString_isPanagram_shouldReturnFailure() { String input = null; - assertFalse(Pangram.isPanagram(input)); - assertFalse(Pangram.isPanagramWithStreams(input)); - assertFalse(Pangram.isPerfectPanagram(input)); + assertFalse(Pangram.isPangram(input)); + assertFalse(Pangram.isPangramWithStreams(input)); + assertFalse(Pangram.isPerfectPangram(input)); } @Test public void givenPerfectPanagramString_isPerfectPanagram_shouldReturnSuccess() { String input = "abcdefghijklmNoPqrStuVwxyz"; - assertTrue(Pangram.isPerfectPanagram(input)); + assertTrue(Pangram.isPerfectPangram(input)); } @Test public void givenNonPanagramString_isPanagram_shouldReturnFailure() { String input = "invalid panagram"; - assertFalse(Pangram.isPanagram(input)); - assertFalse(Pangram.isPanagramWithStreams(input)); + assertFalse(Pangram.isPangram(input)); + assertFalse(Pangram.isPangramWithStreams(input)); } @Test public void givenPanagram_isPerfectPanagram_shouldReturnFailure() { String input = "Two driven jocks help fax my big quiz"; - assertFalse(Pangram.isPerfectPanagram(input)); + assertFalse(Pangram.isPerfectPangram(input)); } } From cd3f0fcb1f1a4e782a470ad66da197be0a2aab1b Mon Sep 17 00:00:00 2001 From: Dhananjay Singh Date: Fri, 4 Jan 2019 05:10:26 +0530 Subject: [PATCH 063/139] BAEL-2391 Two pointer technique * two pointer technique * Corrected two sum * Changed asserts in unit test --- .../LinkedListFindMiddle.java | 16 ++++++ .../twopointertechnique/MyNode.java | 20 +++++++ .../twopointertechnique/RotateArray.java | 22 ++++++++ .../twopointertechnique/TwoSum.java | 38 +++++++++++++ .../LinkedListFindMiddleUnitTest.java | 37 ++++++++++++ .../RotateArrayUnitTest.java | 26 +++++++++ .../twopointertechnique/TwoSumUnitTest.java | 56 +++++++++++++++++++ 7 files changed, 215 insertions(+) create mode 100644 algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java create mode 100644 algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java create mode 100644 algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java create mode 100644 algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java create mode 100644 algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java create mode 100644 algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java create mode 100644 algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java new file mode 100644 index 0000000000..a7031f4fba --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddle.java @@ -0,0 +1,16 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class LinkedListFindMiddle { + + public T findMiddle(MyNode head) { + MyNode slowPointer = head; + MyNode fastPointer = head; + + while (fastPointer.next != null && fastPointer.next.next != null) { + fastPointer = fastPointer.next.next; + slowPointer = slowPointer.next; + } + return slowPointer.data; + } + +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java new file mode 100644 index 0000000000..7d93f03ef9 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/MyNode.java @@ -0,0 +1,20 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class MyNode { + MyNode next; + E data; + + public MyNode(E value) { + data = value; + next = null; + } + + public MyNode(E value, MyNode n) { + data = value; + next = n; + } + + public void setNext(MyNode n) { + next = n; + } +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java new file mode 100644 index 0000000000..b4e3698c01 --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/RotateArray.java @@ -0,0 +1,22 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class RotateArray { + + public void rotate(int[] input, int step) { + step %= input.length; + reverse(input, 0, input.length - 1); + reverse(input, 0, step - 1); + reverse(input, step, input.length - 1); + } + + private void reverse(int[] input, int start, int end) { + while (start < end) { + int temp = input[start]; + input[start] = input[end]; + input[end] = temp; + start++; + end--; + } + } + +} diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java new file mode 100644 index 0000000000..14eceaa1bd --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/twopointertechnique/TwoSum.java @@ -0,0 +1,38 @@ +package com.baeldung.algorithms.twopointertechnique; + +public class TwoSum { + + public boolean twoSum(int[] input, int targetValue) { + + int pointerOne = 0; + int pointerTwo = input.length - 1; + + while (pointerOne < pointerTwo) { + int sum = input[pointerOne] + input[pointerTwo]; + + if (sum == targetValue) { + return true; + } else if (sum < targetValue) { + pointerOne++; + } else { + pointerTwo--; + } + } + + return false; + } + + public boolean twoSumSlow(int[] input, int targetValue) { + + for (int i = 0; i < input.length; i++) { + for (int j = 1; j < input.length; j++) { + if (input[i] + input[j] == targetValue) { + return true; + } + } + } + + return false; + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java new file mode 100644 index 0000000000..422a53fa3e --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/LinkedListFindMiddleUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class LinkedListFindMiddleUnitTest { + + LinkedListFindMiddle linkedListFindMiddle = new LinkedListFindMiddle(); + + @Test + public void givenLinkedListOfMyNodes_whenLinkedListFindMiddle_thenCorrect() { + + MyNode head = createNodesList(8); + + assertThat(linkedListFindMiddle.findMiddle(head)).isEqualTo("4"); + + head = createNodesList(9); + + assertThat(linkedListFindMiddle.findMiddle(head)).isEqualTo("5"); + } + + private static MyNode createNodesList(int n) { + + MyNode head = new MyNode("1"); + MyNode current = head; + + for (int i = 2; i <= n; i++) { + MyNode newNode = new MyNode(String.valueOf(i)); + current.setNext(newNode); + current = newNode; + } + + return head; + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java new file mode 100644 index 0000000000..da227ae751 --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/RotateArrayUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class RotateArrayUnitTest { + + private RotateArray rotateArray = new RotateArray(); + + private int[] inputArray; + + private int step; + + @Test + public void givenAnArrayOfIntegers_whenRotateKsteps_thenCorrect() { + + inputArray = new int[] { 1, 2, 3, 4, 5, 6, 7 }; + step = 4; + + rotateArray.rotate(inputArray, step); + + assertThat(inputArray).containsExactly(new int[] { 4, 5, 6, 7, 1, 2, 3 }); + } + +} diff --git a/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java new file mode 100644 index 0000000000..aa76f8e1cf --- /dev/null +++ b/algorithms-miscellaneous-1/src/test/java/com/baeldung/algorithms/twopointertechnique/TwoSumUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.algorithms.twopointertechnique; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TwoSumUnitTest { + + private TwoSum twoSum = new TwoSum(); + + private int[] sortedArray; + + private int targetValue; + + @Test + public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 12; + + assertTrue(twoSum.twoSumSlow(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSumSlow_thenPairDoesNotExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 20; + + assertFalse(twoSum.twoSumSlow(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSum_thenPairExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 12; + + assertTrue(twoSum.twoSum(sortedArray, targetValue)); + } + + @Test + public void givenASortedArrayOfIntegers_whenTwoSum_thenPairDoesNotExists() { + + sortedArray = new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 }; + + targetValue = 20; + + assertFalse(twoSum.twoSum(sortedArray, targetValue)); + } + +} From b62edd2503d91dca0096f7a39379bb03f7cdbbf7 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:16:51 +0530 Subject: [PATCH 064/139] backlink added --- core-kotlin/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 05f07e7e7e..de989ce141 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -47,3 +47,4 @@ - [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt) - [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) - [Generate a Random Alphanumeric String in Kotlin](https://www.baeldung.com/kotlin-random-alphanumeric-string) +- [Kotlin Contracts](https://www.baeldung.com/kotlin-contracts) From 8d3e2c9b0791cc48dc9c5141974d2f792eb16983 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:20:24 +0530 Subject: [PATCH 065/139] backlink added --- core-kotlin/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-kotlin/README.md b/core-kotlin/README.md index de989ce141..609a30a1a8 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -48,3 +48,4 @@ - [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) - [Generate a Random Alphanumeric String in Kotlin](https://www.baeldung.com/kotlin-random-alphanumeric-string) - [Kotlin Contracts](https://www.baeldung.com/kotlin-contracts) +- [Operator Overloading in Kotlin](https://www.baeldung.com/kotlin-operator-overloading) From 58ddffc6cb344776aee93a625bf9804068934a7d Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:24:15 +0530 Subject: [PATCH 066/139] backlink-added --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index e973907248..d1ebff1d8a 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -24,3 +24,4 @@ - [Hibernate 5 Bootstrapping API](https://www.baeldung.com/hibernate-5-bootstrapping-api) - [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel) - [Guide to the Hibernate EntityManager](https://www.baeldung.com/hibernate-entitymanager) +- [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) From b2d0f6cc832bb310028d755f4dc45f3e8df9fb1c Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:26:20 +0530 Subject: [PATCH 067/139] backlink added --- java-strings/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-strings/README.md b/java-strings/README.md index fa048dbb5a..a86f6e73c3 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -46,4 +46,5 @@ - [Replace a Character at a Specific Index in a String in Java](https://www.baeldung.com/java-replace-character-at-index) - [Convert a Comma Separated String to a List in Java](https://www.baeldung.com/java-string-with-separator-to-list) - [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) -- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) \ No newline at end of file +- [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) +- [Remove Leading and Trailing Characters from a String](https://www.baeldung.com/java-remove-trailing-characters) From 703890941d21986f26504f52eea68484446c960a Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:28:11 +0530 Subject: [PATCH 068/139] back-link added --- core-java/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java/README.md b/core-java/README.md index 03b77186b0..5aee69d9a9 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -45,3 +45,4 @@ - [Guide to Character Encoding](https://www.baeldung.com/java-char-encoding) - [Graphs in Java](https://www.baeldung.com/java-graphs) - [Console I/O in Java](http://www.baeldung.com/java-console-input-output) +- [Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) From 48f3db9713b4797973df4092e1500f1d5d315aed Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:30:45 +0530 Subject: [PATCH 069/139] back-link added --- java-collections-maps/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/java-collections-maps/README.md b/java-collections-maps/README.md index 0b76ca1959..b4ab270448 100644 --- a/java-collections-maps/README.md +++ b/java-collections-maps/README.md @@ -18,3 +18,4 @@ - [Merging Two Maps with Java 8](https://www.baeldung.com/java-merge-maps) - [How to Check If a Key Exists in a Map](https://www.baeldung.com/java-map-key-exists) - [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps) +- [Immutable Map Implementations in Java](https://www.baeldung.com/java-immutable-maps) From e20cf9ac43a05ae558d68aba8cf031c0cd459264 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:32:02 +0530 Subject: [PATCH 070/139] back-link added --- algorithms-miscellaneous-1/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index a725bbd141..59765588b0 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -12,4 +12,5 @@ - [Check If a String Contains All The Letters of The Alphabet](https://www.baeldung.com/java-string-contains-all-letters) - [Find the Middle Element of a Linked List](http://www.baeldung.com/java-linked-list-middle-element) - [Calculate Factorial in Java](https://www.baeldung.com/java-calculate-factorial) -- [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings) \ No newline at end of file +- [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings) +- [Find the Longest Substring without Repeating Characters](https://www.baeldung.com/java-longest-substring-without-repeated-characters) From 129630109b387ace7543e0d000d7bdd9d2ff5d7d Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:35:15 +0530 Subject: [PATCH 071/139] back-link added --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index d1ebff1d8a..5f826eec73 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -25,3 +25,4 @@ - [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel) - [Guide to the Hibernate EntityManager](https://www.baeldung.com/hibernate-entitymanager) - [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) +- [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one) From c91211b4e67841dac61be31bd823f3a7831103a9 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:36:49 +0530 Subject: [PATCH 072/139] back-link added --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index 5f826eec73..fbcf1c94bb 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -26,3 +26,4 @@ - [Guide to the Hibernate EntityManager](https://www.baeldung.com/hibernate-entitymanager) - [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) - [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one) +- [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query) From ca08f5ff9d0c1c2c2502e501aa9d57927e65562d Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:38:08 +0530 Subject: [PATCH 073/139] back-link added --- spring-5-reactive/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-5-reactive/README.md b/spring-5-reactive/README.md index 2a4ee017f4..c39bb616f8 100644 --- a/spring-5-reactive/README.md +++ b/spring-5-reactive/README.md @@ -18,3 +18,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Validation for Functional Endpoints in Spring 5](https://www.baeldung.com/spring-functional-endpoints-validation) - [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) - [Testing Reactive Streams Using StepVerifier and TestPublisher](https://www.baeldung.com/reactive-streams-step-verifier-test-publisher) +- [Debugging Reactive Streams in Spring 5](https://www.baeldung.com/spring-debugging-reactive-streams) From 52269334d931b748fbb0e338cbfdf2394487050f Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:41:30 +0530 Subject: [PATCH 074/139] back-link added --- java-streams/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/java-streams/README.md b/java-streams/README.md index 2550f08650..33ca2619a8 100644 --- a/java-streams/README.md +++ b/java-streams/README.md @@ -14,3 +14,4 @@ - [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams) - [Stream Ordering in Java](https://www.baeldung.com/java-stream-ordering) - [Introduction to Protonpack](https://www.baeldung.com/java-protonpack) +- [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda) From 45924c75ead9d0add259a42b2ad6927440aaece5 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:42:37 +0530 Subject: [PATCH 075/139] backlink added --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index fbcf1c94bb..512370e853 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -27,3 +27,4 @@ - [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) - [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one) - [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query) +- [Using c3p0 with Hibernate](https://www.baeldung.com/hibernate-c3p0) From c5ddf0178f658ac74cd6e5c6f625722b7f824be9 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:44:10 +0530 Subject: [PATCH 076/139] backlink added --- spring-boot-ops/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-ops/README.md b/spring-boot-ops/README.md index c125c96c36..553b02ebf0 100644 --- a/spring-boot-ops/README.md +++ b/spring-boot-ops/README.md @@ -9,4 +9,4 @@ - [Shutdown a Spring Boot Application](http://www.baeldung.com/spring-boot-shutdown) - [Spring Boot Console Application](http://www.baeldung.com/spring-boot-console-app) - [Comparing Embedded Servlet Containers in Spring Boot](http://www.baeldung.com/spring-boot-servlet-containers) - + - [Programmatically Restarting a Spring Boot Application](https://www.baeldung.com/java-restart-spring-boot-app) From 83795f942119caae01148be5417690a0d6d8cc81 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:46:02 +0530 Subject: [PATCH 077/139] Backlink added --- persistence-modules/spring-data-jpa/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/spring-data-jpa/README.md b/persistence-modules/spring-data-jpa/README.md index 3c71600565..976a692699 100644 --- a/persistence-modules/spring-data-jpa/README.md +++ b/persistence-modules/spring-data-jpa/README.md @@ -18,6 +18,7 @@ - [Limiting Query Results with JPA and Spring Data JPA](https://www.baeldung.com/jpa-limit-query-results) - [Sorting Query Results with Spring Data](https://www.baeldung.com/spring-data-sorting) - [INSERT Statement in JPA](https://www.baeldung.com/jpa-insert) +- [Pagination and Sorting using Spring Data JPA](https://www.baeldung.com/spring-data-jpa-pagination-sorting) ### Eclipse Config After importing the project into Eclipse, you may see the following error: From 25eed099f34cb085a08b4a2a027677fb36051b60 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:47:44 +0530 Subject: [PATCH 078/139] backlink added --- core-kotlin/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 609a30a1a8..0ce4b74d91 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -49,3 +49,4 @@ - [Generate a Random Alphanumeric String in Kotlin](https://www.baeldung.com/kotlin-random-alphanumeric-string) - [Kotlin Contracts](https://www.baeldung.com/kotlin-contracts) - [Operator Overloading in Kotlin](https://www.baeldung.com/kotlin-operator-overloading) +- [Inline Classes in Kotlin](https://www.baeldung.com/kotlin-inline-classes) From 1c120d1886b8399f8ce9c2d287d3b25c09245fa0 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:49:44 +0530 Subject: [PATCH 079/139] backlink added --- core-java-11/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-11/README.md b/core-java-11/README.md index 181ada3f45..c8039f4bc5 100644 --- a/core-java-11/README.md +++ b/core-java-11/README.md @@ -2,4 +2,4 @@ - [Java 11 Single File Source Code](https://www.baeldung.com/java-single-file-source-code) - [Java 11 Local Variable Syntax for Lambda Parameters](https://www.baeldung.com/java-var-lambda-params) - +- [Java 11 String API Additions](https://www.baeldung.com/java-11-string-api) From cd5d9da8c072a9bf86d2552d0a36cac7c415cca1 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:53:20 +0530 Subject: [PATCH 080/139] Backlink added --- lombok-custom/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lombok-custom/README.md diff --git a/lombok-custom/README.md b/lombok-custom/README.md new file mode 100644 index 0000000000..bfc784ea7e --- /dev/null +++ b/lombok-custom/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [Implementing a Custom Lombok Annotation](https://www.baeldung.com/lombok-custom-annotation) From c8fcad8b6a0bda2fae75090d0171e7799921e2b8 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:54:37 +0530 Subject: [PATCH 081/139] backlink added --- core-java-arrays/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-arrays/README.md b/core-java-arrays/README.md index 56110585ac..400dd7793c 100644 --- a/core-java-arrays/README.md +++ b/core-java-arrays/README.md @@ -13,3 +13,4 @@ - [How to Invert an Array in Java](http://www.baeldung.com/java-invert-array) - [Array Operations in Java](http://www.baeldung.com/java-common-array-operations) - [Intersection Between two Integer Arrays](https://www.baeldung.com/java-array-intersection) +- [Sorting Arrays in Java](https://www.baeldung.com/java-sorting-arrays) From e67486cf739cf245ede5757332bc84c340e6c6b3 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:55:40 +0530 Subject: [PATCH 082/139] backlink added --- gson/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/gson/README.md b/gson/README.md index e1eb155f43..4edd7158d4 100644 --- a/gson/README.md +++ b/gson/README.md @@ -9,3 +9,4 @@ - [Exclude Fields from Serialization in Gson](http://www.baeldung.com/gson-exclude-fields-serialization) - [Save Data to a JSON File with Gson](https://www.baeldung.com/gson-save-file) - [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map) +- [Working with Primitive Values in Gson](https://www.baeldung.com/java-gson-primitives) From e67dae8b6b0483791aab0a1c7e151a2a91bdf6c1 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:56:40 +0530 Subject: [PATCH 083/139] backlink added --- jee-7/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/jee-7/README.md b/jee-7/README.md index a2493e561b..a783e7860e 100644 --- a/jee-7/README.md +++ b/jee-7/README.md @@ -5,3 +5,4 @@ - [Introduction to JAX-WS](http://www.baeldung.com/jax-ws) - [A Guide to Java EE Web-Related Annotations](http://www.baeldung.com/javaee-web-annotations) - [Introduction to Testing with Arquillian](http://www.baeldung.com/arquillian) +- [Java EE 7 Batch Processing](https://www.baeldung.com/java-ee-7-batch-processing) From c31163f54f5ecd7dfd79ced4c761b5dbf28168a9 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:57:55 +0530 Subject: [PATCH 084/139] backlink added --- core-kotlin/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 0ce4b74d91..225ad87e87 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -50,3 +50,4 @@ - [Kotlin Contracts](https://www.baeldung.com/kotlin-contracts) - [Operator Overloading in Kotlin](https://www.baeldung.com/kotlin-operator-overloading) - [Inline Classes in Kotlin](https://www.baeldung.com/kotlin-inline-classes) +- [Creating Java static final Equivalents in Kotlin](https://www.baeldung.com/kotlin-java-static-final) From 5e7ca37b760c7e570ede5b0f1cd25bf103d6007d Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 17:58:56 +0530 Subject: [PATCH 085/139] Backlink added --- spring-cloud/spring-cloud-kubernetes/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-cloud/spring-cloud-kubernetes/README.md b/spring-cloud/spring-cloud-kubernetes/README.md index 295ead1c2f..2387758626 100644 --- a/spring-cloud/spring-cloud-kubernetes/README.md +++ b/spring-cloud/spring-cloud-kubernetes/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Running Spring Boot Applications With Minikube](https://www.baeldung.com/spring-boot-minikube) +- [Self-Healing Applications with Kubernetes and Spring Boot](https://www.baeldung.com/spring-boot-kubernetes-self-healing-apps) From eaa57758366e7d08d788929b59528fa112179824 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 18:00:24 +0530 Subject: [PATCH 086/139] backlink added --- persistence-modules/hibernate5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md index 512370e853..03bdd9b759 100644 --- a/persistence-modules/hibernate5/README.md +++ b/persistence-modules/hibernate5/README.md @@ -28,3 +28,4 @@ - [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one) - [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query) - [Using c3p0 with Hibernate](https://www.baeldung.com/hibernate-c3p0) +- [Persist a JSON Object Using Hibernate](https://www.baeldung.com/hibernate-persist-json-object) From 6afe91c171f28aa0c6f70e2afc9c2252b82652e3 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 18:01:35 +0530 Subject: [PATCH 087/139] backlink added --- core-java-collections/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-collections/README.md b/core-java-collections/README.md index 1a90d01a82..f549adaa4f 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -30,3 +30,4 @@ - [Join and Split Arrays and Collections in Java](http://www.baeldung.com/java-join-and-split) - [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) - [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) +- [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) From 8b2af060dfb5befd3c2d0423aee9052f5d707b81 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 18:03:13 +0530 Subject: [PATCH 088/139] backlink added --- akka-http/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 akka-http/README.md diff --git a/akka-http/README.md b/akka-http/README.md new file mode 100644 index 0000000000..3831b5079f --- /dev/null +++ b/akka-http/README.md @@ -0,0 +1,3 @@ +## Relevant articles: + +- [Introduction to Akka HTTP](https://www.baeldung.com/akka-http) From 35744e704426ddc034a5248c62c912e243c02722 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 18:04:15 +0530 Subject: [PATCH 089/139] backlink added --- core-java-collections/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-collections/README.md b/core-java-collections/README.md index f549adaa4f..bde0f9fdb9 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -31,3 +31,4 @@ - [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) - [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) - [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) +- [Differences Between HashMap and Hashtable](https://www.baeldung.com/hashmap-hashtable-differences) From dd45e825d455ffa6d5d41869f144030202feb576 Mon Sep 17 00:00:00 2001 From: collaboratewithakash <38683470+collaboratewithakash@users.noreply.github.com> Date: Fri, 4 Jan 2019 18:06:27 +0530 Subject: [PATCH 090/139] backlink added --- java-strings/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/java-strings/README.md b/java-strings/README.md index a86f6e73c3..08fbec35ab 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -48,3 +48,4 @@ - [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter) - [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) - [Remove Leading and Trailing Characters from a String](https://www.baeldung.com/java-remove-trailing-characters) +- [Concatenating Strings In Java](https://www.baeldung.com/java-strings-concatenation) From d5ab82475deb7e451db519bfbd37092f1e6f6f5b Mon Sep 17 00:00:00 2001 From: Olaniyi Anjola Date: Fri, 4 Jan 2019 11:44:24 -0500 Subject: [PATCH 091/139] BAEL-2452: Using curl from Java (#6043) * BAEL-2452: Using curl from Java * A re-do of the examples using tests, instead of main class * Fix un-used variable --- .../baeldung/curltojava/JavaCurlExamples.java | 29 ++++++++++ .../curltojava/JavaCurlExamplesUnitTest.java | 55 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java create mode 100644 core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java diff --git a/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java b/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java new file mode 100644 index 0000000000..166b0ecb13 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/curltojava/JavaCurlExamples.java @@ -0,0 +1,29 @@ +package com.baeldung.curltojava; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class JavaCurlExamples { + + public static String inputStreamToString(InputStream inputStream) { + final int bufferSize = 8 * 1024; + byte[] buffer = new byte[bufferSize]; + final StringBuilder builder = new StringBuilder(); + try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream, bufferSize)) { + while (bufferedInputStream.read(buffer) != -1) { + builder.append(new String(buffer)); + } + } catch (IOException ex) { + Logger.getLogger(JavaCurlExamples.class.getName()).log(Level.SEVERE, null, ex); + } + return builder.toString(); + } + + public static void consumeInputStream(InputStream inputStream) { + inputStreamToString(inputStream); + } + +} diff --git a/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java new file mode 100644 index 0000000000..4e82059f2b --- /dev/null +++ b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.curltojava; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import org.junit.Assert; +import org.junit.Test; + +public class JavaCurlExamplesUnitTest { + + + @Test + public void givenCommand_whenCalled_thenProduceZeroExitCode() throws IOException { + String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; + ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + processBuilder.directory(new File("/home/")); + Process process = processBuilder.start(); + InputStream inputStream = process.getInputStream(); + // Consume the inputStream so the process can exit + JavaCurlExamples.consumeInputStream(inputStream); + int exitCode = process.exitValue(); + + Assert.assertEquals(0, exitCode); + } + + @Test + public void givenNewCommands_whenCalled_thenCheckIfIsAlive() throws IOException { + String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; + ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + processBuilder.directory(new File("/home/")); + Process process = processBuilder.start(); + + // Re-use processBuilder + processBuilder.command(new String[]{"newCommand", "arguments"}); + + Assert.assertEquals(true, process.isAlive()); + } + + @Test + public void whenRequestGet_thenReturnSuccessResponseCode() throws IOException { + String url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2"; + URL urlObj = new URL(url); + HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("GET"); + connection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode()); + } + +} From 082724abecd4bc514baadc96b4a3046570254609 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Sat, 5 Jan 2019 10:38:13 +0530 Subject: [PATCH 092/139] BAEL-2536-addressed review comments --- .../java/com/baeldung/string/Pangram.java | 6 ++-- .../com/baeldung/string/PangramUnitTest.java | 29 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/java-strings/src/main/java/com/baeldung/string/Pangram.java b/java-strings/src/main/java/com/baeldung/string/Pangram.java index 8498a7074a..c09b0c1d29 100644 --- a/java-strings/src/main/java/com/baeldung/string/Pangram.java +++ b/java-strings/src/main/java/com/baeldung/string/Pangram.java @@ -15,10 +15,10 @@ public class Pangram { Boolean[] alphabetMarker = new Boolean[ALPHABET_COUNT]; Arrays.fill(alphabetMarker, false); int alphabetIndex = 0; - str = str.toUpperCase(); + String strUpper = str.toUpperCase(); for (int i = 0; i < str.length(); i++) { - if ('A' <= str.charAt(i) && str.charAt(i) <= 'Z') { - alphabetIndex = str.charAt(i) - 'A'; + if ('A' <= strUpper.charAt(i) && strUpper.charAt(i) <= 'Z') { + alphabetIndex = strUpper.charAt(i) - 'A'; alphabetMarker[alphabetIndex] = true; } } diff --git a/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java index 67523a4524..36e603b535 100644 --- a/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/PangramUnitTest.java @@ -4,39 +4,38 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; - public class PangramUnitTest { - + @Test - public void givenValidString_isPanagram_shouldReturnSuccess() { + public void givenValidString_isPangram_shouldReturnSuccess() { String input = "Two driven jocks help fax my big quiz"; - assertTrue(Pangram.isPangram(input)); - assertTrue(Pangram.isPangramWithStreams(input)); + assertTrue(Pangram.isPangram(input)); + assertTrue(Pangram.isPangramWithStreams(input)); } - + @Test - public void givenNullString_isPanagram_shouldReturnFailure() { + public void givenNullString_isPangram_shouldReturnFailure() { String input = null; assertFalse(Pangram.isPangram(input)); assertFalse(Pangram.isPangramWithStreams(input)); assertFalse(Pangram.isPerfectPangram(input)); } - + @Test - public void givenPerfectPanagramString_isPerfectPanagram_shouldReturnSuccess() { + public void givenPerfectPangramString_isPerfectPangram_shouldReturnSuccess() { String input = "abcdefghijklmNoPqrStuVwxyz"; - assertTrue(Pangram.isPerfectPangram(input)); + assertTrue(Pangram.isPerfectPangram(input)); } - + @Test - public void givenNonPanagramString_isPanagram_shouldReturnFailure() { - String input = "invalid panagram"; + public void givenNonPangramString_isPangram_shouldReturnFailure() { + String input = "invalid pangram"; assertFalse(Pangram.isPangram(input)); assertFalse(Pangram.isPangramWithStreams(input)); } - + @Test - public void givenPanagram_isPerfectPanagram_shouldReturnFailure() { + public void givenPangram_isPerfectPangram_shouldReturnFailure() { String input = "Two driven jocks help fax my big quiz"; assertFalse(Pangram.isPerfectPangram(input)); } From 833285f2ba1407fda131542e2c261d5763f2f656 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 5 Jan 2019 11:12:31 +0200 Subject: [PATCH 093/139] Update README.md --- core-java-collections-list/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-collections-list/README.md b/core-java-collections-list/README.md index aba53f5b30..a35e714006 100644 --- a/core-java-collections-list/README.md +++ b/core-java-collections-list/README.md @@ -24,4 +24,5 @@ - [Java List Initialization in One Line](https://www.baeldung.com/java-init-list-one-line) - [Ways to Iterate Over a List in Java](https://www.baeldung.com/java-iterate-list) - [ClassCastException: Arrays$ArrayList cannot be cast to ArrayList](https://www.baeldung.com/java-classcastexception-arrays-arraylist) -- [Flattening Nested Collections in Java](http://www.baeldung.com/java-flatten-nested-collections) \ No newline at end of file +- [Flattening Nested Collections in Java](http://www.baeldung.com/java-flatten-nested-collections) +- [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) From ceb41607f0d406080bffe30fad8f450feab0f06f Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 5 Jan 2019 11:13:39 +0200 Subject: [PATCH 094/139] Update README.md --- core-java-collections/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/core-java-collections/README.md b/core-java-collections/README.md index bde0f9fdb9..be83621429 100644 --- a/core-java-collections/README.md +++ b/core-java-collections/README.md @@ -30,5 +30,4 @@ - [Join and Split Arrays and Collections in Java](http://www.baeldung.com/java-join-and-split) - [A Guide to EnumMap](https://www.baeldung.com/java-enum-map) - [A Guide to Iterator in Java](http://www.baeldung.com/java-iterator) -- [Intersection of Two Lists in Java](https://www.baeldung.com/java-lists-intersection) - [Differences Between HashMap and Hashtable](https://www.baeldung.com/hashmap-hashtable-differences) From b1352b58e08542038ab4973a16617a205e1b3226 Mon Sep 17 00:00:00 2001 From: Kumar Chandrakant Date: Sat, 5 Jan 2019 17:52:23 +0530 Subject: [PATCH 095/139] Adding files for the tutorial BAEL-2301 (#6066) --- apache-spark/pom.xml | 68 ++++++++- .../java/com/baeldung/data/pipeline/Word.java | 25 ++++ .../data/pipeline/WordCountingApp.java | 116 +++++++++++++++ .../WordCountingAppWithCheckpoint.java | 140 ++++++++++++++++++ 4 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java create mode 100644 apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java create mode 100644 apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java diff --git a/apache-spark/pom.xml b/apache-spark/pom.xml index 290b63a14d..b05b97198d 100644 --- a/apache-spark/pom.xml +++ b/apache-spark/pom.xml @@ -15,16 +15,76 @@ - org.apache.spark - spark-core_2.10 + spark-core_2.11 ${org.apache.spark.spark-core.version} + provided + + org.apache.spark + spark-sql_2.11 + ${org.apache.spark.spark-sql.version} + provided + + + org.apache.spark + spark-streaming_2.11 + ${org.apache.spark.spark-streaming.version} + provided + + + org.apache.spark + spark-streaming-kafka-0-10_2.11 + ${org.apache.spark.spark-streaming-kafka.version} + + + com.datastax.spark + spark-cassandra-connector_2.11 + ${com.datastax.spark.spark-cassandra-connector.version} + + + com.datastax.spark + spark-cassandra-connector-java_2.11 + ${com.datastax.spark.spark-cassandra-connector-java.version} + - + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + + + - 2.2.0 + 2.3.0 + 2.3.0 + 2.3.0 + 2.3.0 + 2.3.0 + 1.5.2 diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java new file mode 100644 index 0000000000..b0caa468b1 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/Word.java @@ -0,0 +1,25 @@ +package com.baeldung.data.pipeline; + +import java.io.Serializable; + +public class Word implements Serializable { + private static final long serialVersionUID = 1L; + private String word; + private int count; + Word(String word, int count) { + this.word = word; + this.count = count; + } + public String getWord() { + return word; + } + public void setWord(String word) { + this.word = word; + } + public int getCount() { + return count; + } + public void setCount(int count) { + this.count = count; + } +} \ No newline at end of file diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java new file mode 100644 index 0000000000..08695b3631 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java @@ -0,0 +1,116 @@ +package com.baeldung.data.pipeline; + +import static com.datastax.spark.connector.japi.CassandraJavaUtil.javaFunctions; +import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaPairRDD; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.function.FlatMapFunction; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.api.java.function.PairFunction; +import org.apache.spark.api.java.function.VoidFunction; +import org.apache.spark.streaming.Durations; +import org.apache.spark.streaming.api.java.JavaDStream; +import org.apache.spark.streaming.api.java.JavaInputDStream; +import org.apache.spark.streaming.api.java.JavaPairDStream; +import org.apache.spark.streaming.api.java.JavaStreamingContext; +import org.apache.spark.streaming.kafka010.ConsumerStrategies; +import org.apache.spark.streaming.kafka010.KafkaUtils; +import org.apache.spark.streaming.kafka010.LocationStrategies; + +import scala.Tuple2; + +public class WordCountingApp { + + @SuppressWarnings("serial") + public static void main(String[] args) throws InterruptedException { + Logger.getLogger("org") + .setLevel(Level.OFF); + Logger.getLogger("akka") + .setLevel(Level.OFF); + + Map kafkaParams = new HashMap<>(); + kafkaParams.put("bootstrap.servers", "localhost:9092"); + kafkaParams.put("key.deserializer", StringDeserializer.class); + kafkaParams.put("value.deserializer", StringDeserializer.class); + kafkaParams.put("group.id", "use_a_separate_group_id_for_each_stream"); + kafkaParams.put("auto.offset.reset", "latest"); + kafkaParams.put("enable.auto.commit", false); + + Collection topics = Arrays.asList("messages"); + + SparkConf sparkConf = new SparkConf(); + sparkConf.setMaster("local[2]"); + sparkConf.setAppName("WordCountingApp"); + sparkConf.set("spark.cassandra.connection.host", "127.0.0.1"); + + JavaStreamingContext streamingContext = new JavaStreamingContext(sparkConf, Durations.seconds(1)); + + JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); + + JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { + @Override + public Tuple2 call(ConsumerRecord record) { + return new Tuple2<>(record.key(), record.value()); + } + }); + + JavaDStream lines = results.map(new Function, String>() { + @Override + public String call(Tuple2 tuple2) { + return tuple2._2(); + } + }); + + JavaDStream words = lines.flatMap(new FlatMapFunction() { + @Override + public Iterator call(String x) { + return Arrays.asList(x.split("\\s+")) + .iterator(); + } + }); + + JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { + @Override + public Tuple2 call(String s) { + return new Tuple2<>(s, 1); + } + }) + .reduceByKey(new Function2() { + @Override + public Integer call(Integer i1, Integer i2) { + return i1 + i2; + } + }); + + wordCounts.foreachRDD(new VoidFunction>() { + @Override + public void call(JavaPairRDD javaRdd) throws Exception { + Map wordCountMap = javaRdd.collectAsMap(); + for (String key : wordCountMap.keySet()) { + List words = Arrays.asList(new Word(key, wordCountMap.get(key))); + JavaRDD rdd = streamingContext.sparkContext() + .parallelize(words); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); + } + } + }); + + streamingContext.start(); + streamingContext.awaitTermination(); + } +} \ No newline at end of file diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java new file mode 100644 index 0000000000..e20b910635 --- /dev/null +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java @@ -0,0 +1,140 @@ +package com.baeldung.data.pipeline; + +import static com.datastax.spark.connector.japi.CassandraJavaUtil.javaFunctions; +import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.spark.SparkConf; +import org.apache.spark.api.java.JavaPairRDD; +import org.apache.spark.api.java.JavaRDD; +import org.apache.spark.api.java.JavaSparkContext; +import org.apache.spark.api.java.Optional; +import org.apache.spark.api.java.function.FlatMapFunction; +import org.apache.spark.api.java.function.Function; +import org.apache.spark.api.java.function.Function2; +import org.apache.spark.api.java.function.Function3; +import org.apache.spark.api.java.function.PairFunction; +import org.apache.spark.api.java.function.VoidFunction; +import org.apache.spark.streaming.Durations; +import org.apache.spark.streaming.State; +import org.apache.spark.streaming.StateSpec; +import org.apache.spark.streaming.api.java.JavaDStream; +import org.apache.spark.streaming.api.java.JavaInputDStream; +import org.apache.spark.streaming.api.java.JavaMapWithStateDStream; +import org.apache.spark.streaming.api.java.JavaPairDStream; +import org.apache.spark.streaming.api.java.JavaStreamingContext; +import org.apache.spark.streaming.kafka010.ConsumerStrategies; +import org.apache.spark.streaming.kafka010.KafkaUtils; +import org.apache.spark.streaming.kafka010.LocationStrategies; + +import scala.Tuple2; + +public class WordCountingAppWithCheckpoint { + + public static JavaSparkContext sparkContext; + + @SuppressWarnings("serial") + public static void main(String[] args) throws InterruptedException { + + Logger.getLogger("org") + .setLevel(Level.OFF); + Logger.getLogger("akka") + .setLevel(Level.OFF); + + Map kafkaParams = new HashMap<>(); + kafkaParams.put("bootstrap.servers", "localhost:9092"); + kafkaParams.put("key.deserializer", StringDeserializer.class); + kafkaParams.put("value.deserializer", StringDeserializer.class); + kafkaParams.put("group.id", "use_a_separate_group_id_for_each_stream"); + kafkaParams.put("auto.offset.reset", "latest"); + kafkaParams.put("enable.auto.commit", false); + + Collection topics = Arrays.asList("messages"); + + SparkConf sparkConf = new SparkConf(); + sparkConf.setMaster("local[2]"); + sparkConf.setAppName("WordCountingAppWithCheckpoint"); + sparkConf.set("spark.cassandra.connection.host", "127.0.0.1"); + + JavaStreamingContext streamingContext = new JavaStreamingContext(sparkConf, Durations.seconds(1)); + + sparkContext = streamingContext.sparkContext(); + + streamingContext.checkpoint("./.checkpoint"); + + JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); + + JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { + @Override + public Tuple2 call(ConsumerRecord record) { + return new Tuple2<>(record.key(), record.value()); + } + }); + + JavaDStream lines = results.map(new Function, String>() { + @Override + public String call(Tuple2 tuple2) { + return tuple2._2(); + } + }); + + JavaDStream words = lines.flatMap(new FlatMapFunction() { + @Override + public Iterator call(String x) { + return Arrays.asList(x.split("\\s+")) + .iterator(); + } + }); + + JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { + @Override + public Tuple2 call(String s) { + return new Tuple2<>(s, 1); + } + }) + .reduceByKey(new Function2() { + @Override + public Integer call(Integer i1, Integer i2) { + return i1 + i2; + } + }); + + Function3, State, Tuple2> mappingFunc = (word, one, state) -> { + int sum = one.orElse(0) + (state.exists() ? state.get() : 0); + Tuple2 output = new Tuple2<>(word, sum); + state.update(sum); + return output; + }; + + JavaPairRDD initialRDD = JavaPairRDD.fromJavaRDD(sparkContext.emptyRDD()); + + JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function(mappingFunc) + .initialState(initialRDD)); + + cumulativeWordCounts.foreachRDD(new VoidFunction>>() { + @Override + public void call(JavaRDD> javaRdd) throws Exception { + List> wordCountList = javaRdd.collect(); + for (Tuple2 tuple : wordCountList) { + List words = Arrays.asList(new Word(tuple._1, tuple._2)); + JavaRDD rdd = sparkContext.parallelize(words); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); + } + } + }); + + streamingContext.start(); + streamingContext.awaitTermination(); + } +} \ No newline at end of file From e3e1c84b24458a2a37799568fcdfe06acf3453e6 Mon Sep 17 00:00:00 2001 From: Maiklins Date: Sat, 5 Jan 2019 13:27:25 +0100 Subject: [PATCH 096/139] BAEL-2485 Permutations of an array in Java (#6027) --- .../algorithms/permutation/Permutation.java | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java diff --git a/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java new file mode 100644 index 0000000000..7fedd78ffb --- /dev/null +++ b/algorithms-miscellaneous-1/src/main/java/com/baeldung/algorithms/permutation/Permutation.java @@ -0,0 +1,123 @@ +package com.baeldung.algorithms.permutation; + +import java.util.Arrays; +import java.util.Collections; + +public class Permutation { + + public static void printAllRecursive(T[] elements, char delimiter) { + printAllRecursive(elements.length, elements, delimiter); + } + + public static void printAllRecursive(int n, T[] elements, char delimiter) { + + if(n == 1) { + printArray(elements, delimiter); + } else { + for(int i = 0; i < n-1; i++) { + printAllRecursive(n - 1, elements, delimiter); + if(n % 2 == 0) { + swap(elements, i, n-1); + } else { + swap(elements, 0, n-1); + } + } + printAllRecursive(n - 1, elements, delimiter); + } + } + + public static void printAllIterative(int n, T[] elements, char delimiter) { + + int[] indexes = new int[n]; + for (int i = 0; i < n; i++) { + indexes[i] = 0; + } + + printArray(elements, delimiter); + + int i = 0; + while (i < n) { + if (indexes[i] < i) { + swap(elements, i % 2 == 0 ? 0: indexes[i], i); + printArray(elements, delimiter); + indexes[i]++; + i = 0; + } + else { + indexes[i] = 0; + i++; + } + } + } + + public static > void printAllOrdered(T[] elements, char delimiter) { + + Arrays.sort(elements); + boolean hasNext = true; + + while(hasNext) { + printArray(elements, delimiter); + int k = 0, l = 0; + hasNext = false; + for (int i = elements.length - 1; i > 0; i--) { + if (elements[i].compareTo(elements[i - 1]) > 0) { + k = i - 1; + hasNext = true; + break; + } + } + + for (int i = elements.length - 1; i > k; i--) { + if (elements[i].compareTo(elements[k]) > 0) { + l = i; + break; + } + } + + swap(elements, k, l); + Collections.reverse(Arrays.asList(elements).subList(k + 1, elements.length)); + } + } + + public static void printRandom(T[] elements, char delimiter) { + + Collections.shuffle(Arrays.asList(elements)); + printArray(elements, delimiter); + } + + private static void swap(T[] elements, int a, int b) { + + T tmp = elements[a]; + elements[a] = elements[b]; + elements[b] = tmp; + } + + private static void printArray(T[] elements, char delimiter) { + + String delimiterSpace = delimiter + " "; + for(int i = 0; i < elements.length; i++) { + System.out.print(elements[i] + delimiterSpace); + } + System.out.print('\n'); + } + + public static void main(String[] argv) { + + Integer[] elements = {1,2,3,4}; + + System.out.println("Rec:"); + printAllRecursive(elements, ';'); + + System.out.println("Iter:"); + printAllIterative(elements.length, elements, ';'); + + System.out.println("Orderes:"); + printAllOrdered(elements, ';'); + + System.out.println("Random:"); + printRandom(elements, ';'); + + System.out.println("Random:"); + printRandom(elements, ';'); + } +} From cceb6a022e41bc84b7aa0ddd8a9cb8ea538d9019 Mon Sep 17 00:00:00 2001 From: pcoates33 Date: Sat, 5 Jan 2019 12:39:43 +0000 Subject: [PATCH 097/139] spring-boot ehcache example added (#6012) --- pom.xml | 3 + spring-ehcache/.gitignore | 13 +++ spring-ehcache/README.md | 7 ++ spring-ehcache/checkstyle.xml | 11 +++ spring-ehcache/pom.xml | 87 +++++++++++++++++++ .../com/baeldung/cachetest/Application.java | 13 +++ .../cachetest/config/CacheConfig.java | 57 ++++++++++++ .../cachetest/config/CacheEventLogger.java | 18 ++++ .../cachetest/rest/NumberController.java | 29 +++++++ .../cachetest/service/NumberService.java | 22 +++++ 10 files changed, 260 insertions(+) create mode 100644 spring-ehcache/.gitignore create mode 100644 spring-ehcache/README.md create mode 100644 spring-ehcache/checkstyle.xml create mode 100644 spring-ehcache/pom.xml create mode 100644 spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java create mode 100644 spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java create mode 100644 spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java create mode 100644 spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java create mode 100644 spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java diff --git a/pom.xml b/pom.xml index e8ff86665c..4dba0da173 100644 --- a/pom.xml +++ b/pom.xml @@ -663,6 +663,7 @@ spring-dispatcher-servlet spring-drools + spring-ehcache spring-ejb spring-exceptions @@ -882,6 +883,7 @@ spring-data-rest spring-dispatcher-servlet spring-drools + spring-ehcache spring-freemarker persistence-modules/spring-hibernate-3 persistence-modules/spring-hibernate4 @@ -1370,6 +1372,7 @@ spring-dispatcher-servlet spring-drools + spring-ehcache spring-ejb spring-exceptions diff --git a/spring-ehcache/.gitignore b/spring-ehcache/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/spring-ehcache/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/spring-ehcache/README.md b/spring-ehcache/README.md new file mode 100644 index 0000000000..749441375e --- /dev/null +++ b/spring-ehcache/README.md @@ -0,0 +1,7 @@ +## Spring Ehcache Example Project + +A simple example of using ehcache with spring-boot. + +### Relevant Articles: +- [Spring Boot Ehcache Example](http://www.baeldung.com/spring-ehcache) + diff --git a/spring-ehcache/checkstyle.xml b/spring-ehcache/checkstyle.xml new file mode 100644 index 0000000000..85063a7570 --- /dev/null +++ b/spring-ehcache/checkstyle.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/spring-ehcache/pom.xml b/spring-ehcache/pom.xml new file mode 100644 index 0000000000..b8378617c5 --- /dev/null +++ b/spring-ehcache/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + spring-ehcache + 0.1-SNAPSHOT + spring-ehcache + jar + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-cache + + + javax.cache + cache-api + + + org.ehcache + ehcache + + + + + spring-ehcache + + + src/main/resources + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-maven-plugin.version} + + checkstyle.xml + + + + + check + + + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle-maven-plugin.version} + + checkstyle.xml + + + + + + + + 3.0.0 + false + + + diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java new file mode 100644 index 0000000000..a1ce7a5317 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/Application.java @@ -0,0 +1,13 @@ +package com.baeldung.cachetest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} \ No newline at end of file diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java new file mode 100644 index 0000000000..3cf2309cb9 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheConfig.java @@ -0,0 +1,57 @@ +package com.baeldung.cachetest.config; + +import java.math.BigDecimal; +import java.time.Duration; + +import javax.cache.CacheManager; + +import org.ehcache.config.CacheConfiguration; +import org.ehcache.config.ResourcePools; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder; +import org.ehcache.config.builders.ExpiryPolicyBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; +import org.ehcache.config.units.EntryUnit; +import org.ehcache.config.units.MemoryUnit; +import org.ehcache.event.EventType; +import org.ehcache.jsr107.Eh107Configuration; +import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class CacheConfig { + + private static final int ON_HEAP_CACHE_SIZE_ENTRIES = 2; + private static final int OFF_HEAP_CACHE_SIZE_MB = 10; + private static final int CACHE_EXPIRY_SECONDS = 30; + + @Bean + public JCacheManagerCustomizer jcacheManagerCustomizer() { + return new JCacheManagerCustomizer() { + + @Override + public void customize(CacheManager cacheManager) { + ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder() + .heap(ON_HEAP_CACHE_SIZE_ENTRIES, EntryUnit.ENTRIES) + .offheap(OFF_HEAP_CACHE_SIZE_MB, MemoryUnit.MB).build(); + + CacheEventListenerConfigurationBuilder eventLoggerConfig = CacheEventListenerConfigurationBuilder + .newEventListenerConfiguration(new CacheEventLogger(), EventType.CREATED, EventType.EXPIRED) + .unordered().asynchronous(); + + CacheConfiguration cacheConfiguration = CacheConfigurationBuilder + .newCacheConfigurationBuilder(Long.class, BigDecimal.class, resourcePools) + .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(CACHE_EXPIRY_SECONDS))) + .add(eventLoggerConfig).build(); + + cacheManager.createCache("squareCache", + Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration)); + + } + }; + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java new file mode 100644 index 0000000000..c8ead85f1e --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/config/CacheEventLogger.java @@ -0,0 +1,18 @@ +package com.baeldung.cachetest.config; + +import org.ehcache.event.CacheEvent; +import org.ehcache.event.CacheEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CacheEventLogger implements CacheEventListener { + + private static final Logger log = LoggerFactory.getLogger(CacheEventLogger.class); + + @Override + public void onEvent(CacheEvent cacheEvent) { + log.info("Cache event {} for item with key {}. Old value = {}, New value = {}", cacheEvent.getType(), + cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue()); + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java new file mode 100644 index 0000000000..4115c34cc4 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/rest/NumberController.java @@ -0,0 +1,29 @@ +package com.baeldung.cachetest.rest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.cachetest.service.NumberService; + +@RestController +@RequestMapping(path = "/number", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +public class NumberController { + + private final static Logger log = LoggerFactory.getLogger(NumberController.class); + + @Autowired + private NumberService numberService; + + @GetMapping(path = "/square/{number}") + public String getThing(@PathVariable Long number) { + log.info("call numberService to square {}", number); + return String.format("{\"square\": %s}", numberService.square(number)); + } + +} diff --git a/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java b/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java new file mode 100644 index 0000000000..bcd930f5e1 --- /dev/null +++ b/spring-ehcache/src/main/java/com/baeldung/cachetest/service/NumberService.java @@ -0,0 +1,22 @@ +package com.baeldung.cachetest.service; + +import java.math.BigDecimal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +public class NumberService { + + private final static Logger log = LoggerFactory.getLogger(NumberService.class); + + @Cacheable(value = "squareCache", key = "#number", condition = "#number>10") + public BigDecimal square(Long number) { + BigDecimal square = BigDecimal.valueOf(number).multiply(BigDecimal.valueOf(number)); + log.info("square of {} is {}", number, square); + return square; + } + +} From b5c29f0e1b556229ad9f29412cbecdcd62da7bb7 Mon Sep 17 00:00:00 2001 From: amit2103 Date: Sat, 5 Jan 2019 20:11:29 +0530 Subject: [PATCH 098/139] [BAEL-11403] - Moved DoubleToString and DoubleToStringUnitTest to java-numbers module --- .../src/main/java/com/baeldung/string/DoubleToString.java | 0 .../src/test/java/com/baeldung/string/DoubleToStringUnitTest.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {core-java => java-numbers}/src/main/java/com/baeldung/string/DoubleToString.java (100%) rename {core-java => java-numbers}/src/test/java/com/baeldung/string/DoubleToStringUnitTest.java (100%) diff --git a/core-java/src/main/java/com/baeldung/string/DoubleToString.java b/java-numbers/src/main/java/com/baeldung/string/DoubleToString.java similarity index 100% rename from core-java/src/main/java/com/baeldung/string/DoubleToString.java rename to java-numbers/src/main/java/com/baeldung/string/DoubleToString.java diff --git a/core-java/src/test/java/com/baeldung/string/DoubleToStringUnitTest.java b/java-numbers/src/test/java/com/baeldung/string/DoubleToStringUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/string/DoubleToStringUnitTest.java rename to java-numbers/src/test/java/com/baeldung/string/DoubleToStringUnitTest.java From bcc848f6a71688ead0c5d61d32abe3a53a984982 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 5 Jan 2019 18:35:47 +0200 Subject: [PATCH 099/139] Update DoubleToString.java --- .../src/main/java/com/baeldung/string/DoubleToString.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-numbers/src/main/java/com/baeldung/string/DoubleToString.java b/java-numbers/src/main/java/com/baeldung/string/DoubleToString.java index d26d26f3df..dd55ba51ad 100644 --- a/java-numbers/src/main/java/com/baeldung/string/DoubleToString.java +++ b/java-numbers/src/main/java/com/baeldung/string/DoubleToString.java @@ -38,4 +38,5 @@ public class DoubleToString { return df.format(d); } + } From 9c45b7eda8e7f2eea9bc9ef8fd45d28fd9608db1 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 5 Jan 2019 18:44:33 +0200 Subject: [PATCH 100/139] Update README.MD --- spring-boot-testing/README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-testing/README.MD b/spring-boot-testing/README.MD index a609b5bf09..144c3581f7 100644 --- a/spring-boot-testing/README.MD +++ b/spring-boot-testing/README.MD @@ -4,3 +4,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles: - [Testing with Spring and Spock](https://www.baeldung.com/spring-spock-testing) +- [Exclude Auto-Configuration Classes in Spring Boot Tests](https://www.baeldung.com/spring-boot-exclude-auto-configuration-test) From 994cb303a0595e96c0ec699a70e323391fe9366a Mon Sep 17 00:00:00 2001 From: dupirefr Date: Sat, 5 Jan 2019 19:03:14 +0100 Subject: [PATCH 101/139] [BAEL-2424] Added classes and tests --- .../com/baeldung/reflection/Employee.java | 7 + .../baeldung/reflection/MonthEmployee.java | 7 + .../java/com/baeldung/reflection/Person.java | 8 ++ .../PersonAndEmployeeReflectionTest.java | 128 ++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/reflection/Employee.java create mode 100644 core-java/src/main/java/com/baeldung/reflection/MonthEmployee.java create mode 100644 core-java/src/main/java/com/baeldung/reflection/Person.java create mode 100644 core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java diff --git a/core-java/src/main/java/com/baeldung/reflection/Employee.java b/core-java/src/main/java/com/baeldung/reflection/Employee.java new file mode 100644 index 0000000000..833cf26b14 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/reflection/Employee.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection; + +public class Employee extends Person { + + public int employeeId; + +} diff --git a/core-java/src/main/java/com/baeldung/reflection/MonthEmployee.java b/core-java/src/main/java/com/baeldung/reflection/MonthEmployee.java new file mode 100644 index 0000000000..697ecc1500 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/reflection/MonthEmployee.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection; + +public class MonthEmployee extends Employee { + + private double reward; + +} diff --git a/core-java/src/main/java/com/baeldung/reflection/Person.java b/core-java/src/main/java/com/baeldung/reflection/Person.java new file mode 100644 index 0000000000..23b312cdd9 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/reflection/Person.java @@ -0,0 +1,8 @@ +package com.baeldung.reflection; + +public class Person { + + public String lastName; + private String firstName; + +} diff --git a/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java b/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java new file mode 100644 index 0000000000..034e54ee93 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java @@ -0,0 +1,128 @@ +package com.baeldung.reflection; + +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +public class PersonAndEmployeeReflectionTest { + + // Fields names + private static final String LAST_NAME_FIELD = "lastName"; + private static final String FIRST_NAME_FIELD = "firstName"; + private static final String EMPLOYEE_ID_FIELD = "employeeId"; + private static final String MONTH_EMPLOYEE_REWARD_FIELD = "reward"; + + @Test + public void givenPersonClass_whenGetDeclaredFields_thenTwoFields() { + // When + Field[] allFields = Person.class.getDeclaredFields(); + + // Then + assertEquals(2, allFields.length); + + Field lastNameField = allFields[0]; + assertEquals(LAST_NAME_FIELD, lastNameField.getName()); + assertEquals(String.class, lastNameField.getType()); + + Field firstNameField = allFields[1]; + assertEquals(FIRST_NAME_FIELD, firstNameField.getName()); + assertEquals(String.class, firstNameField.getType()); + } + + @Test + public void givenEmployeeClass_whenSuperClassGetDeclaredFields_thenOneField() { + // When + Field[] allFields = Employee.class.getSuperclass().getDeclaredFields(); + + // Then + assertEquals(2, allFields.length); + + Field lastNameField = allFields[0]; + assertEquals(LAST_NAME_FIELD, lastNameField.getName()); + assertEquals(String.class, lastNameField.getType()); + + Field firstNameField = allFields[1]; + assertEquals(FIRST_NAME_FIELD, firstNameField.getName()); + assertEquals(String.class, firstNameField.getType()); + } + + @Test + public void givenEmployeeClass_whenGetDeclaredFields_thenOneField() { + // When + Field[] allFields = Employee.class.getDeclaredFields(); + + // Then + assertEquals(1, allFields.length); + + Field employeeIdField = allFields[0]; + assertEquals(EMPLOYEE_ID_FIELD, employeeIdField.getName()); + assertEquals(int.class, employeeIdField.getType()); + } + + @Test + public void givenEmployeeClass_whenGetDeclaredFieldsOnBothClasses_thenThreeFields() { + // When + Field[] personFields = Employee.class.getSuperclass().getDeclaredFields(); + Field[] employeeFields = Employee.class.getDeclaredFields(); + Field[] allFields = new Field[employeeFields.length + personFields.length]; + Arrays.setAll(allFields, i -> (i < personFields.length ? personFields[i] : employeeFields[i - personFields.length])); + + // Then + assertEquals(3, allFields.length); + + Field lastNameField = allFields[0]; + assertEquals(LAST_NAME_FIELD, lastNameField.getName()); + assertEquals(String.class, lastNameField.getType()); + + Field firstNameField = allFields[1]; + assertEquals(FIRST_NAME_FIELD, firstNameField.getName()); + assertEquals(String.class, firstNameField.getType()); + + Field employeeIdField = allFields[2]; + assertEquals(EMPLOYEE_ID_FIELD, employeeIdField.getName()); + assertEquals(int.class, employeeIdField.getType()); + } + + @Test + public void givenMonthEmployeeClass_whenGetAllFields_thenFourFields() { + // When + List allFields = getAllFields(MonthEmployee.class); + + // Then + assertEquals(4, allFields.size()); + + Field lastNameField = allFields.get(0); + assertEquals(LAST_NAME_FIELD, lastNameField.getName()); + assertEquals(String.class, lastNameField.getType()); + + Field firstNameField = allFields.get(1); + assertEquals(FIRST_NAME_FIELD, firstNameField.getName()); + assertEquals(String.class, firstNameField.getType()); + + Field employeeIdField = allFields.get(2); + assertEquals(EMPLOYEE_ID_FIELD, employeeIdField.getName()); + assertEquals(int.class, employeeIdField.getType()); + + Field monthEmployeeRewardField = allFields.get(3); + assertEquals(MONTH_EMPLOYEE_REWARD_FIELD, monthEmployeeRewardField.getName()); + assertEquals(double.class, monthEmployeeRewardField.getType()); + } + + public List getAllFields(Class clazz) { + if (clazz == null) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + result.addAll(getAllFields(clazz.getSuperclass())); + result.addAll(Arrays.asList(clazz.getDeclaredFields())); + return result; + } + +} \ No newline at end of file From fe44881bb15a18497d1fb8f25c78db52dd4cf91d Mon Sep 17 00:00:00 2001 From: pandachris Date: Sun, 6 Jan 2019 01:21:28 +0700 Subject: [PATCH 102/139] BAEL-2565 (#6077) * BAEL-2565 * BAEL-2565 Test code consistency --- .../com/baeldung/enums/values/Element1.java | 17 ++++ .../com/baeldung/enums/values/Element2.java | 52 ++++++++++ .../com/baeldung/enums/values/Element3.java | 63 ++++++++++++ .../com/baeldung/enums/values/Element4.java | 95 +++++++++++++++++++ .../com/baeldung/enums/values/Labeled.java | 5 + .../enums/values/Element1UnitTest.java | 48 ++++++++++ .../enums/values/Element2UnitTest.java | 59 ++++++++++++ .../enums/values/Element3UnitTest.java | 57 +++++++++++ .../enums/values/Element4UnitTest.java | 71 ++++++++++++++ 9 files changed, 467 insertions(+) create mode 100644 core-java-8/src/main/java/com/baeldung/enums/values/Element1.java create mode 100644 core-java-8/src/main/java/com/baeldung/enums/values/Element2.java create mode 100644 core-java-8/src/main/java/com/baeldung/enums/values/Element3.java create mode 100644 core-java-8/src/main/java/com/baeldung/enums/values/Element4.java create mode 100644 core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java create mode 100644 core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java create mode 100644 core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java create mode 100644 core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java create mode 100644 core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element1.java b/core-java-8/src/main/java/com/baeldung/enums/values/Element1.java new file mode 100644 index 0000000000..6c80adacb1 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/enums/values/Element1.java @@ -0,0 +1,17 @@ +package com.baeldung.enums.values; + +/** + * This is a simple enum of periodic table elements + */ +public enum Element1 { + H, + HE, + LI, + BE, + B, + C, + N, + O, + F, + NE +} diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element2.java b/core-java-8/src/main/java/com/baeldung/enums/values/Element2.java new file mode 100644 index 0000000000..28bf3a475a --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/enums/values/Element2.java @@ -0,0 +1,52 @@ +package com.baeldung.enums.values; + +/** + * The simple enum has been enhanced to add the name of the element. + */ +public enum Element2 { + H("Hydrogen"), + HE("Helium"), + LI("Lithium"), + BE("Beryllium"), + B("Boron"), + C("Carbon"), + N("Nitrogen"), + O("Oxygen"), + F("Flourine"), + NE("Neon"); + + /** a final variable to store the label, which can't be changed */ + public final String label; + + /** + * A private constructor that sets the label. + * @param label + */ + private Element2(String label) { + this.label = label; + } + + /** + * Look up Element2 instances by the label field. This implementation iterates through + * the values() list to find the label. + * @param label The label to look up + * @return The Element2 instance with the label, or null if not found. + */ + public static Element2 valueOfLabel(String label) { + for (Element2 e2 : values()) { + if (e2.label.equals(label)) { + return e2; + } + } + return null; + } + + /** + * Override the toString() method to return the label instead of the declared name. + * @return + */ + @Override + public String toString() { + return this.label; + } +} diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element3.java b/core-java-8/src/main/java/com/baeldung/enums/values/Element3.java new file mode 100644 index 0000000000..cb98695de8 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/enums/values/Element3.java @@ -0,0 +1,63 @@ +package com.baeldung.enums.values; + +import java.util.HashMap; +import java.util.Map; + +/** + * A Map has been added to cache labels for faster lookup. + */ +public enum Element3 { + H("Hydrogen"), + HE("Helium"), + LI("Lithium"), + BE("Beryllium"), + B("Boron"), + C("Carbon"), + N("Nitrogen"), + O("Oxygen"), + F("Flourine"), + NE("Neon"); + + /** + * A map to cache labels and their associated Element3 instances. + * Note that this only works if the labels are all unique! + */ + private static final Map BY_LABEL = new HashMap<>(); + + /** populate the BY_LABEL cache */ + static { + for (Element3 e3 : values()) { + BY_LABEL.put(e3.label, e3); + } + } + + /** a final variable to store the label, which can't be changed */ + public final String label; + + /** + * A private constructor that sets the label. + * @param label + */ + private Element3(String label) { + this.label = label; + } + + /** + * Look up Element2 instances by the label field. This implementation finds the + * label in the BY_LABEL cache. + * @param label The label to look up + * @return The Element3 instance with the label, or null if not found. + */ + public static Element3 valueOfLabel(String label) { + return BY_LABEL.get(label); + } + + /** + * Override the toString() method to return the label instead of the declared name. + * @return + */ + @Override + public String toString() { + return this.label; + } +} diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element4.java b/core-java-8/src/main/java/com/baeldung/enums/values/Element4.java new file mode 100644 index 0000000000..89c45f9d1b --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/enums/values/Element4.java @@ -0,0 +1,95 @@ +package com.baeldung.enums.values; + +import java.util.HashMap; +import java.util.Map; + +/** + * Multiple fields have been added and the Labeled interface is implemented. + */ +public enum Element4 implements Labeled { + H("Hydrogen", 1, 1.008f), + HE("Helium", 2, 4.0026f), + LI("Lithium", 3, 6.94f), + BE("Beryllium", 4, 9.01722f), + B("Boron", 5, 10.81f), + C("Carbon", 6, 12.011f), + N("Nitrogen", 7, 14.007f), + O("Oxygen", 8, 15.999f), + F("Flourine", 9, 18.998f), + NE("Neon", 10, 20.180f); + /** + * Maps cache labels and their associated Element3 instances. + * Note that this only works if the values are all unique! + */ + private static final Map BY_LABEL = new HashMap<>(); + private static final Map BY_ATOMIC_NUMBER = new HashMap<>(); + private static final Map BY_ATOMIC_WEIGHT = new HashMap<>(); + + /** populate the caches */ + static { + for (Element4 e4 : values()) { + BY_LABEL.put(e4.label, e4); + BY_ATOMIC_NUMBER.put(e4.atomicNumber, e4); + BY_ATOMIC_WEIGHT.put(e4.atomicWeight, e4); + } + } + + /** final variables to store the values, which can't be changed */ + public final String label; + public final int atomicNumber; + public final float atomicWeight; + + private Element4(String label, int atomicNumber, float atomicWeight) { + this.label = label; + this.atomicNumber = atomicNumber; + this.atomicWeight = atomicWeight; + } + + /** + * Implement the Labeled interface. + * @return the label value + */ + @Override + public String label() { + return label; + } + + /** + * Look up Element2 instances by the label field. This implementation finds the + * label in the BY_LABEL cache. + * @param label The label to look up + * @return The Element4 instance with the label, or null if not found. + */ + public static Element4 valueOfLabel(String label) { + return BY_LABEL.get(label); + } + + /** + * Look up Element2 instances by the atomicNumber field. This implementation finds the + * atomicNUmber in the cache. + * @param number The atomicNumber to look up + * @return The Element4 instance with the label, or null if not found. + */ + public static Element4 valueOfAtomicNumber(int number) { + return BY_ATOMIC_NUMBER.get(number); + } + + /** + * Look up Element2 instances by the atomicWeight field. This implementation finds the + * atomic weight in the cache. + * @param weight the atomic weight to look up + * @return The Element4 instance with the label, or null if not found. + */ + public static Element4 valueOfAtomicWeight(float weight) { + return BY_ATOMIC_WEIGHT.get(weight); + } + + /** + * Override the toString() method to return the label instead of the declared name. + * @return + */ + @Override + public String toString() { + return this.label; + } +} diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java b/core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java new file mode 100644 index 0000000000..e41d6525f1 --- /dev/null +++ b/core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java @@ -0,0 +1,5 @@ +package com.baeldung.enums.values; + +public interface Labeled { + String label(); +} diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java b/core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java new file mode 100644 index 0000000000..ab3e684230 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.enums.values; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author chris + */ +public class Element1UnitTest { + + public Element1UnitTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void whenAccessingToString_thenItShouldEqualName() { + for (Element1 e1 : Element1.values()) { + assertEquals(e1.name(), e1.toString()); + } + } + + @Test + public void whenCallingValueOf_thenReturnTheCorrectEnum() { + for (Element1 e1 : Element1.values()) { + assertSame(e1, Element1.valueOf(e1.name())); + } + } +} diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java b/core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java new file mode 100644 index 0000000000..02995a2f41 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java @@ -0,0 +1,59 @@ +/* + * 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.baeldung.enums.values; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author chris + */ +public class Element2UnitTest { + private static final Logger LOGGER = LoggerFactory.getLogger(Element2UnitTest.class); + + public Element2UnitTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void whenLocatebyLabel_thenReturnCorrectValue() { + for (Element2 e2 : Element2.values()) { + assertSame(e2, Element2.valueOfLabel(e2.label)); + } + } + + /** + * Test of toString method, of class Element2. + */ + @Test + public void whenCallingToString_thenReturnLabel() { + for (Element2 e2 : Element2.values()) { + assertEquals(e2.label, e2.toString()); + } + } +} diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java b/core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java new file mode 100644 index 0000000000..40c76a97b1 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java @@ -0,0 +1,57 @@ +/* + * 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.baeldung.enums.values; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author chris + */ +public class Element3UnitTest { + + public Element3UnitTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void whenLocatebyLabel_thenReturnCorrectValue() { + for (Element3 e3 : Element3.values()) { + assertSame(e3, Element3.valueOfLabel(e3.label)); + } + } + + /** + * Test of toString method, of class Element3. + */ + @Test + public void whenCallingToString_thenReturnLabel() { + for (Element3 e3 : Element3.values()) { + assertEquals(e3.label, e3.toString()); + } + } + +} diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java b/core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java new file mode 100644 index 0000000000..d349dcef72 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java @@ -0,0 +1,71 @@ +/* + * 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.baeldung.enums.values; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author chris + */ +public class Element4UnitTest { + + public Element4UnitTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void whenLocatebyLabel_thenReturnCorrectValue() { + for (Element4 e4 : Element4.values()) { + assertSame(e4, Element4.valueOfLabel(e4.label)); + } + } + + @Test + public void whenLocatebyAtmNum_thenReturnCorrectValue() { + for (Element4 e4 : Element4.values()) { + assertSame(e4, Element4.valueOfAtomicNumber(e4.atomicNumber)); + } + } + + @Test + public void whenLocatebyAtmWt_thenReturnCorrectValue() { + for (Element4 e4 : Element4.values()) { + assertSame(e4, Element4.valueOfAtomicWeight(e4.atomicWeight)); + } + } + + /** + * Test of toString method, of class Element4. + */ + @Test + public void whenCallingToString_thenReturnLabel() { + for (Element4 e4 : Element4.values()) { + assertEquals(e4.label, e4.toString()); + } + } + +} From 2d8ea6d287b2542ba7b4e5a13e3711d613b65ea8 Mon Sep 17 00:00:00 2001 From: kyleandari <44148335+kyleandari@users.noreply.github.com> Date: Sat, 5 Jan 2019 13:25:22 -0500 Subject: [PATCH 103/139] Bael 2431 (#6073) * Adding code to java core and deleting it from java-8 * removing failed unittest * removing space --- .../com/baeldung/interfaces/Electronic.java | 22 ---------------- .../com/baeldung/interfaces/Motorcycle.java | 10 ------- .../java/com/baeldung/interfaces/Truck.java | 8 ------ .../java/com/baeldung/interfaces/Vehicle.java | 6 ----- .../interfaces/multiinheritance/Vehicle.java | 13 ---------- .../interfaces/polymorphysim/Circle.java | 25 ------------------ .../polymorphysim/DisplayShape.java | 26 ------------------- .../polymorphysim/FunctionalMain.java | 23 ---------------- .../polymorphysim/MainPolymorphic.java | 15 ----------- .../interfaces/polymorphysim/Shape.java | 9 ------- .../interfaces/polymorphysim/Square.java | 25 ------------------ .../interfaces/PolymorphysimUnitTest.java | 26 ------------------- .../java/com/baeldung/interfaces/Box.java | 5 ++++ .../com/baeldung/interfaces/Employee.java | 1 - .../interfaces/EmployeeSalaryComparator.java | 7 +++-- .../com/baeldung/interfaces/HasColor.java | 3 +-- .../interfaces/multiinheritance/Car.java | 3 ++- .../interfaces/multiinheritance/Fly.java | 3 ++- .../multiinheritance/Transform.java | 0 .../interfaces/multiinheritance/Vehicle.java | 4 +++ .../interfaces/polymorphysim/Circle.java | 9 +++++++ .../polymorphysim/MainTestClass.java | 20 ++++++++++++++ .../interfaces/polymorphysim/Shape.java | 6 +++++ .../interfaces/polymorphysim/Square.java | 9 +++++++ 24 files changed, 61 insertions(+), 217 deletions(-) delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/Electronic.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/Motorcycle.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/Truck.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/Vehicle.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/DisplayShape.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/FunctionalMain.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/MainPolymorphic.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java delete mode 100644 core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java delete mode 100644 core-java-8/src/test/java/com/baeldung/interfaces/PolymorphysimUnitTest.java create mode 100644 core-java/src/main/java/com/baeldung/interfaces/Box.java rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/Employee.java (99%) rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java (67%) rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/HasColor.java (66%) rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java (84%) rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java (69%) rename {core-java-8 => core-java}/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java (100%) create mode 100644 core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java create mode 100644 core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java create mode 100644 core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java create mode 100644 core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java create mode 100644 core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/Electronic.java b/core-java-8/src/main/java/com/baeldung/interfaces/Electronic.java deleted file mode 100644 index bfbc381483..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/Electronic.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.interfaces; - -public interface Electronic { - //Constant variable - public static final String LED = "LED"; - - //Abstract method - public int getElectricityUse(); - - // Static method - public static boolean isEnergyEfficient(String electtronicType) { - if (electtronicType.equals(LED)) { - return true; - } - return false; - } - - //Default method - public default void printDescription() { - System.out.println("Electronic Description"); - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/Motorcycle.java b/core-java-8/src/main/java/com/baeldung/interfaces/Motorcycle.java deleted file mode 100644 index 6003f476a3..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/Motorcycle.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.baeldung.interfaces; - -import com.baeldung.interfaces.multiinheritance.Transform; - -public class Motorcycle implements Transform { - @Override - public void transform() { - // Implementation - } -} \ No newline at end of file diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/Truck.java b/core-java-8/src/main/java/com/baeldung/interfaces/Truck.java deleted file mode 100644 index d78de23371..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/Truck.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.baeldung.interfaces; - -public class Truck extends Vehicle { - @Override - public void transform() { - // implementation - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/Vehicle.java b/core-java-8/src/main/java/com/baeldung/interfaces/Vehicle.java deleted file mode 100644 index 8b4662e1a3..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/Vehicle.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.baeldung.interfaces; - -import com.baeldung.interfaces.multiinheritance.Transform; - -public abstract class Vehicle implements Transform { -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java b/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java deleted file mode 100644 index fb0d36e3e0..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.interfaces.multiinheritance; - -public class Vehicle implements Fly, Transform { - @Override - public void fly() { - System.out.println("I can Fly!!"); - } - - @Override - public void transform() { - System.out.println("I can Transform!!"); - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java deleted file mode 100644 index afb3142d96..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -public class Circle implements Shape { - - private double radius; - - public Circle(double radius){ - this.radius = radius; - } - - @Override - public String name() { - return "Circle"; - } - - @Override - public double area() { - return Math.PI * (radius * radius); - } - - @Override - public String getColor() { - return "green"; - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/DisplayShape.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/DisplayShape.java deleted file mode 100644 index d9c9dd107a..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/DisplayShape.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -import java.util.ArrayList; - -public class DisplayShape { - - private ArrayList shapes; - - public ArrayList getShapes() { - return shapes; - } - - public DisplayShape() { - shapes = new ArrayList<>(); - } - - public void add(Shape shape) { - shapes.add(shape); - } - - public void display() { - for (Shape shape : shapes) { - System.out.println(shape.name() + " area: " + shape.area()); - } - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/FunctionalMain.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/FunctionalMain.java deleted file mode 100644 index 5316dd7db7..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/FunctionalMain.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -import java.util.function.Predicate; - -public class FunctionalMain { - -public static void main(String[] args) { - Shape circleShape = new Circle(2); - Shape squareShape = new Square(2); - - DisplayShape DisplayShape = new DisplayShape(); - DisplayShape.add(circleShape); - DisplayShape.add(squareShape); - - Predicate checkArea = (shape) -> shape.area() < 5; - - for (Shape shape : DisplayShape.getShapes()) { - if (checkArea.test(shape)) { - System.out.println(shape.name() + " " + shape.area()); - } - } -} -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/MainPolymorphic.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/MainPolymorphic.java deleted file mode 100644 index cc43c1300b..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/MainPolymorphic.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -public class MainPolymorphic { - public static void main(String[] args){ - - Shape circleShape = new Circle(2); - Shape squareShape = new Square(2); - - DisplayShape displayShape = new DisplayShape(); - displayShape.add(circleShape); - displayShape.add(squareShape); - - displayShape.display(); - } -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java deleted file mode 100644 index 560e07a80a..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -import com.baeldung.interfaces.HasColor; - -public interface Shape extends HasColor { - - public abstract String name(); - public abstract double area(); -} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java b/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java deleted file mode 100644 index 00b75ace20..0000000000 --- a/core-java-8/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.interfaces.polymorphysim; - -public class Square implements Shape { - - private double width; - - public Square(double width) { - this.width = width; - } - - @Override - public String name() { - return "Square"; - } - - @Override - public double area() { - return width * width; - } - - @Override - public String getColor() { - return "red"; - } -} diff --git a/core-java-8/src/test/java/com/baeldung/interfaces/PolymorphysimUnitTest.java b/core-java-8/src/test/java/com/baeldung/interfaces/PolymorphysimUnitTest.java deleted file mode 100644 index 7ded5e6621..0000000000 --- a/core-java-8/src/test/java/com/baeldung/interfaces/PolymorphysimUnitTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.interfaces; - -import com.baeldung.interfaces.polymorphysim.Circle; -import com.baeldung.interfaces.polymorphysim.Shape; -import com.baeldung.interfaces.polymorphysim.Square; -import org.assertj.core.api.Assertions; -import org.junit.Test; - -public class PolymorphysimUnitTest { - - @Test - public void whenInterfacePointsToCircle_CircleAreaMethodisBeingCalled(){ - double expectedArea = 12.566370614359172; - Shape circle = new Circle(2); - double actualArea = circle.area(); - Assertions.assertThat(actualArea).isEqualTo(expectedArea); - } - - @Test - public void whenInterfacePointsToSquare_SquareAreaMethodisBeingCalled(){ - double expectedArea = 4; - Shape square = new Square(2); - double actualArea = square.area(); - Assertions.assertThat(actualArea).isEqualTo(expectedArea); - } -} diff --git a/core-java/src/main/java/com/baeldung/interfaces/Box.java b/core-java/src/main/java/com/baeldung/interfaces/Box.java new file mode 100644 index 0000000000..0bb6560465 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/Box.java @@ -0,0 +1,5 @@ +package com.baeldung.interfaces; + +public interface Box extends HasColor { + int getHeight(); +} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/Employee.java b/core-java/src/main/java/com/baeldung/interfaces/Employee.java similarity index 99% rename from core-java-8/src/main/java/com/baeldung/interfaces/Employee.java rename to core-java/src/main/java/com/baeldung/interfaces/Employee.java index 903bc81e6f..8c6bd3f7f3 100644 --- a/core-java-8/src/main/java/com/baeldung/interfaces/Employee.java +++ b/core-java/src/main/java/com/baeldung/interfaces/Employee.java @@ -11,5 +11,4 @@ public class Employee { public void setSalary(double salary) { this.salary = salary; } - } diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java b/core-java/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java similarity index 67% rename from core-java-8/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java rename to core-java/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java index cfa4226c1a..5c841b7c2b 100644 --- a/core-java-8/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java +++ b/core-java/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java @@ -6,12 +6,11 @@ public class EmployeeSalaryComparator implements Comparator { @Override public int compare(Employee employeeA, Employee employeeB) { - - if(employeeA.getSalary() < employeeB.getSalary()){ + if (employeeA.getSalary() < employeeB.getSalary()) { return -1; - }else if(employeeA.getSalary() > employeeB.getSalary()){ + } else if (employeeA.getSalary() > employeeB.getSalary()) { return 1; - }else{ + } else { return 0; } } diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/HasColor.java b/core-java/src/main/java/com/baeldung/interfaces/HasColor.java similarity index 66% rename from core-java-8/src/main/java/com/baeldung/interfaces/HasColor.java rename to core-java/src/main/java/com/baeldung/interfaces/HasColor.java index 6eface2d47..d9688ea866 100644 --- a/core-java-8/src/main/java/com/baeldung/interfaces/HasColor.java +++ b/core-java/src/main/java/com/baeldung/interfaces/HasColor.java @@ -1,5 +1,4 @@ package com.baeldung.interfaces; public interface HasColor { - public String getColor(); -} \ No newline at end of file +} diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java similarity index 84% rename from core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java rename to core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java index b951fc0273..d9b30a1e7b 100644 --- a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java +++ b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java @@ -1,6 +1,7 @@ package com.baeldung.interfaces.multiinheritance; -public class Car implements Fly, Transform { +public class Car implements Fly,Transform { + @Override public void fly() { System.out.println("I can Fly!!"); diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java similarity index 69% rename from core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java rename to core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java index d84182aec6..611e51c67b 100644 --- a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java +++ b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java @@ -1,5 +1,6 @@ package com.baeldung.interfaces.multiinheritance; -public abstract interface Fly{ +public interface Fly { + void fly(); } diff --git a/core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java rename to core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java new file mode 100644 index 0000000000..be25e112ee --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java @@ -0,0 +1,4 @@ +package com.baeldung.interfaces.multiinheritance; + +public abstract class Vehicle implements Transform { +} diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java new file mode 100644 index 0000000000..b4d97bd53a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java @@ -0,0 +1,9 @@ +package com.baeldung.interfaces.polymorphysim; + +public class Circle implements Shape { + + @Override + public String name() { + return "Circle"; + } +} diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java new file mode 100644 index 0000000000..5cce3c3af0 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java @@ -0,0 +1,20 @@ +package com.baeldung.interfaces.polymorphysim; + +import java.util.ArrayList; +import java.util.List; + +public class MainTestClass { + + public static void main(String[] args) { + List shapes = new ArrayList<>(); + Shape circleShape = new Circle(); + Shape squareShape = new Square(); + + shapes.add(circleShape); + shapes.add(squareShape); + + for (Shape shape : shapes) { + System.out.println(shape.name()); + } + } +} diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java new file mode 100644 index 0000000000..885dc73de2 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java @@ -0,0 +1,6 @@ +package com.baeldung.interfaces.polymorphysim; + +public interface Shape { + + String name(); +} diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java new file mode 100644 index 0000000000..c17bdd902d --- /dev/null +++ b/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java @@ -0,0 +1,9 @@ +package com.baeldung.interfaces.polymorphysim; + +public class Square implements Shape { + + @Override + public String name() { + return "Square"; + } +} From 1d14de6b4b2a2fba456967a38a9e9623e925d5a2 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 5 Jan 2019 22:39:29 +0200 Subject: [PATCH 104/139] Update and rename PersonAndEmployeeReflectionTest.java to PersonAndEmployeeReflectionUnitTest.java --- ...tionTest.java => PersonAndEmployeeReflectionUnitTest.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename core-java/src/test/java/com/baeldung/reflection/{PersonAndEmployeeReflectionTest.java => PersonAndEmployeeReflectionUnitTest.java} (98%) diff --git a/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java b/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java similarity index 98% rename from core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java rename to core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java index 034e54ee93..c051f165f1 100644 --- a/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionTest.java +++ b/core-java/src/test/java/com/baeldung/reflection/PersonAndEmployeeReflectionUnitTest.java @@ -10,7 +10,7 @@ import java.util.List; import static org.junit.Assert.*; -public class PersonAndEmployeeReflectionTest { +public class PersonAndEmployeeReflectionUnitTest { // Fields names private static final String LAST_NAME_FIELD = "lastName"; @@ -125,4 +125,4 @@ public class PersonAndEmployeeReflectionTest { return result; } -} \ No newline at end of file +} From cd4be8ce9eba7905eecb78dd1195bc2ca7936ac5 Mon Sep 17 00:00:00 2001 From: kyleandari <44148335+kyleandari@users.noreply.github.com> Date: Sat, 5 Jan 2019 15:56:01 -0500 Subject: [PATCH 105/139] moving code from java-core to java-core-lang (#6084) --- .../src/main/java/com/baeldung/interfaces/Box.java | 0 .../src/main/java/com/baeldung/interfaces/Employee.java | 0 .../java/com/baeldung/interfaces/EmployeeSalaryComparator.java | 0 .../src/main/java/com/baeldung/interfaces/HasColor.java | 0 .../main/java/com/baeldung/interfaces/multiinheritance/Car.java | 0 .../main/java/com/baeldung/interfaces/multiinheritance/Fly.java | 0 .../java/com/baeldung/interfaces/multiinheritance/Transform.java | 0 .../java/com/baeldung/interfaces/multiinheritance/Vehicle.java | 0 .../main/java/com/baeldung/interfaces/polymorphysim/Circle.java | 0 .../java/com/baeldung/interfaces/polymorphysim/MainTestClass.java | 0 .../main/java/com/baeldung/interfaces/polymorphysim/Shape.java | 0 .../main/java/com/baeldung/interfaces/polymorphysim/Square.java | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/Box.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/Employee.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/HasColor.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java (100%) rename {core-java => core-java-lang}/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java (100%) diff --git a/core-java/src/main/java/com/baeldung/interfaces/Box.java b/core-java-lang/src/main/java/com/baeldung/interfaces/Box.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/Box.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/Box.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/Employee.java b/core-java-lang/src/main/java/com/baeldung/interfaces/Employee.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/Employee.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/Employee.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java b/core-java-lang/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/EmployeeSalaryComparator.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/HasColor.java b/core-java-lang/src/main/java/com/baeldung/interfaces/HasColor.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/HasColor.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/HasColor.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java b/core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Car.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java b/core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Fly.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java b/core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Transform.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java b/core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/multiinheritance/Vehicle.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java b/core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Circle.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java b/core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/MainTestClass.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java b/core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Shape.java diff --git a/core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java b/core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java similarity index 100% rename from core-java/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java rename to core-java-lang/src/main/java/com/baeldung/interfaces/polymorphysim/Square.java From 20e8886165192cd55e5151120b07ff0029242e28 Mon Sep 17 00:00:00 2001 From: Kumar Chandrakant Date: Sun, 6 Jan 2019 19:26:21 +0530 Subject: [PATCH 106/139] Kafka spark cassandra (#6078) * Adding files for the tutorial BAEL-2301 * Incorporating review comments on the article. --- .../data/pipeline/WordCountingApp.java | 58 ++++------------ .../WordCountingAppWithCheckpoint.java | 66 +++++-------------- 2 files changed, 29 insertions(+), 95 deletions(-) diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java index 08695b3631..1155644e1e 100644 --- a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java @@ -6,7 +6,6 @@ import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -35,7 +34,6 @@ import scala.Tuple2; public class WordCountingApp { - @SuppressWarnings("serial") public static void main(String[] args) throws InterruptedException { Logger.getLogger("org") .setLevel(Level.OFF); @@ -61,52 +59,24 @@ public class WordCountingApp { JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); - JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { - @Override - public Tuple2 call(ConsumerRecord record) { - return new Tuple2<>(record.key(), record.value()); - } - }); + JavaPairDStream results = messages.mapToPair((PairFunction, String, String>) record -> new Tuple2<>(record.key(), record.value())); - JavaDStream lines = results.map(new Function, String>() { - @Override - public String call(Tuple2 tuple2) { - return tuple2._2(); - } - }); + JavaDStream lines = results.map((Function, String>) tuple2 -> tuple2._2()); - JavaDStream words = lines.flatMap(new FlatMapFunction() { - @Override - public Iterator call(String x) { - return Arrays.asList(x.split("\\s+")) - .iterator(); - } - }); + JavaDStream words = lines.flatMap((FlatMapFunction) x -> Arrays.asList(x.split("\\s+")) + .iterator()); - JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { - @Override - public Tuple2 call(String s) { - return new Tuple2<>(s, 1); - } - }) - .reduceByKey(new Function2() { - @Override - public Integer call(Integer i1, Integer i2) { - return i1 + i2; - } - }); + JavaPairDStream wordCounts = words.mapToPair((PairFunction) s -> new Tuple2<>(s, 1)) + .reduceByKey((Function2) (i1, i2) -> i1 + i2); - wordCounts.foreachRDD(new VoidFunction>() { - @Override - public void call(JavaPairRDD javaRdd) throws Exception { - Map wordCountMap = javaRdd.collectAsMap(); - for (String key : wordCountMap.keySet()) { - List words = Arrays.asList(new Word(key, wordCountMap.get(key))); - JavaRDD rdd = streamingContext.sparkContext() - .parallelize(words); - javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) - .saveToCassandra(); - } + wordCounts.foreachRDD((VoidFunction>) javaRdd -> { + Map wordCountMap = javaRdd.collectAsMap(); + for (String key : wordCountMap.keySet()) { + List wordList = Arrays.asList(new Word(key, wordCountMap.get(key))); + JavaRDD rdd = streamingContext.sparkContext() + .parallelize(wordList); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); } }); diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java index e20b910635..79e21f7209 100644 --- a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java @@ -6,7 +6,6 @@ import static com.datastax.spark.connector.japi.CassandraJavaUtil.mapToRow; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -15,7 +14,6 @@ import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.spark.SparkConf; -import org.apache.spark.api.java.JavaPairRDD; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.api.java.Optional; @@ -43,7 +41,6 @@ public class WordCountingAppWithCheckpoint { public static JavaSparkContext sparkContext; - @SuppressWarnings("serial") public static void main(String[] args) throws InterruptedException { Logger.getLogger("org") @@ -74,63 +71,30 @@ public class WordCountingAppWithCheckpoint { JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); - JavaPairDStream results = messages.mapToPair(new PairFunction, String, String>() { - @Override - public Tuple2 call(ConsumerRecord record) { - return new Tuple2<>(record.key(), record.value()); - } - }); + JavaPairDStream results = messages.mapToPair((PairFunction, String, String>) record -> new Tuple2<>(record.key(), record.value())); - JavaDStream lines = results.map(new Function, String>() { - @Override - public String call(Tuple2 tuple2) { - return tuple2._2(); - } - }); + JavaDStream lines = results.map((Function, String>) tuple2 -> tuple2._2()); - JavaDStream words = lines.flatMap(new FlatMapFunction() { - @Override - public Iterator call(String x) { - return Arrays.asList(x.split("\\s+")) - .iterator(); - } - }); + JavaDStream words = lines.flatMap((FlatMapFunction) x -> Arrays.asList(x.split("\\s+")) + .iterator()); - JavaPairDStream wordCounts = words.mapToPair(new PairFunction() { - @Override - public Tuple2 call(String s) { - return new Tuple2<>(s, 1); - } - }) - .reduceByKey(new Function2() { - @Override - public Integer call(Integer i1, Integer i2) { - return i1 + i2; - } - }); + JavaPairDStream wordCounts = words.mapToPair((PairFunction) s -> new Tuple2<>(s, 1)) + .reduceByKey((Function2) (i1, i2) -> i1 + i2); - Function3, State, Tuple2> mappingFunc = (word, one, state) -> { + JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function((Function3, State, Tuple2>) (word, one, state) -> { int sum = one.orElse(0) + (state.exists() ? state.get() : 0); Tuple2 output = new Tuple2<>(word, sum); state.update(sum); return output; - }; + })); - JavaPairRDD initialRDD = JavaPairRDD.fromJavaRDD(sparkContext.emptyRDD()); - - JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function(mappingFunc) - .initialState(initialRDD)); - - cumulativeWordCounts.foreachRDD(new VoidFunction>>() { - @Override - public void call(JavaRDD> javaRdd) throws Exception { - List> wordCountList = javaRdd.collect(); - for (Tuple2 tuple : wordCountList) { - List words = Arrays.asList(new Word(tuple._1, tuple._2)); - JavaRDD rdd = sparkContext.parallelize(words); - javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) - .saveToCassandra(); - } + cumulativeWordCounts.foreachRDD((VoidFunction>>) javaRdd -> { + List> wordCountList = javaRdd.collect(); + for (Tuple2 tuple : wordCountList) { + List wordList = Arrays.asList(new Word(tuple._1, tuple._2)); + JavaRDD rdd = sparkContext.parallelize(wordList); + javaFunctions(rdd).writerBuilder("vocabulary", "words", mapToRow(Word.class)) + .saveToCassandra(); } }); From 731a3cd2298232d75ce41fd2ab194f091bca4e36 Mon Sep 17 00:00:00 2001 From: Corneil du Plessis Date: Sun, 6 Jan 2019 16:15:09 +0200 Subject: [PATCH 107/139] BAEL-2104: Spring Boot deployment to AWS Beanstalk (#5951) --- spring-boot-bootstrap/pom.xml | 21 +++++++++++++++++++ .../application-beanstalk.properties | 3 +++ 2 files changed, 24 insertions(+) create mode 100644 spring-boot-bootstrap/src/main/resources/application-beanstalk.properties diff --git a/spring-boot-bootstrap/pom.xml b/spring-boot-bootstrap/pom.xml index 7cafc5aa24..0ffc1820b8 100644 --- a/spring-boot-bootstrap/pom.xml +++ b/spring-boot-bootstrap/pom.xml @@ -57,6 +57,27 @@ + + beanstalk + + ${project.name}-eb + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + **/cloud/config/*.java + + + + + + openshift diff --git a/spring-boot-bootstrap/src/main/resources/application-beanstalk.properties b/spring-boot-bootstrap/src/main/resources/application-beanstalk.properties new file mode 100644 index 0000000000..de03a3b5bb --- /dev/null +++ b/spring-boot-bootstrap/src/main/resources/application-beanstalk.properties @@ -0,0 +1,3 @@ +spring.datasource.url=jdbc:mysql://${rds.hostname}:${rds.port}/${rds.db.name} +spring.datasource.username=${rds.username} +spring.datasource.password=${rds.password} \ No newline at end of file From e89c0948d8b33be57cecf099b189748c2dc7cc29 Mon Sep 17 00:00:00 2001 From: amit2103 Date: Sat, 5 Jan 2019 19:58:09 +0530 Subject: [PATCH 108/139] [BAEL-11415] - Initial commit with sparing-kafka version and topic creation configuration onstatup --- spring-kafka/pom.xml | 2 +- .../spring/kafka/KafkaApplication.java | 18 +++++- .../spring/kafka/KafkaTopicConfig.java | 57 +++++++++++++++++++ .../org/baeldung/SpringContextLiveTest.java | 17 ++++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java create mode 100644 spring-kafka/src/test/java/org/baeldung/SpringContextLiveTest.java diff --git a/spring-kafka/pom.xml b/spring-kafka/pom.xml index 5c370880b4..b76d4f10c0 100644 --- a/spring-kafka/pom.xml +++ b/spring-kafka/pom.xml @@ -33,7 +33,7 @@ - 1.1.3.RELEASE + 2.2.2.RELEASE 2.9.7 diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java index 4ee7f40335..b313eafdb9 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java @@ -13,8 +13,11 @@ import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.TopicPartition; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.kafka.support.SendResult; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.util.concurrent.ListenableFuture; +import org.springframework.util.concurrent.ListenableFutureCallback; @SpringBootApplication public class KafkaApplication { @@ -98,7 +101,20 @@ public class KafkaApplication { private String greetingTopicName; public void sendMessage(String message) { - kafkaTemplate.send(topicName, message); + + ListenableFuture> future = kafkaTemplate.send(topicName, message); + + future.addCallback(new ListenableFutureCallback>() { + + @Override + public void onSuccess(SendResult result) { + System.out.println("Sent message=[" + message + "] with offset=[" + result.getRecordMetadata().offset() + "]"); + } + @Override + public void onFailure(Throwable ex) { + System.out.println("Unable to send message=[" + message + "] due to : " + ex.getMessage()); + } + }); } public void sendMessageToPartion(String message, int partition) { diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java new file mode 100644 index 0000000000..a3426e78a3 --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java @@ -0,0 +1,57 @@ +package com.baeldung.spring.kafka; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaAdmin; + +@Configuration +public class KafkaTopicConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + @Value(value = "${message.topic.name}") + private String topicName; + + @Value(value = "${partitioned.topic.name}") + private String partionedTopicName; + + @Value(value = "${filtered.topic.name}") + private String filteredTopicName; + + @Value(value = "${greeting.topic.name}") + private String greetingTopicName; + + @Bean + public KafkaAdmin kafkaAdmin() { + Map configs = new HashMap<>(); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + return new KafkaAdmin(configs); + } + + @Bean + public NewTopic topic1() { + return new NewTopic(topicName, 1, (short) 1); + } + + @Bean + public NewTopic topic2() { + return new NewTopic(partionedTopicName, 6, (short) 1); + } + + @Bean + public NewTopic topic3() { + return new NewTopic(filteredTopicName, 1, (short) 1); + } + + @Bean + public NewTopic topic4() { + return new NewTopic(greetingTopicName, 1, (short) 1); + } +} diff --git a/spring-kafka/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-kafka/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..d8fb3131f5 --- /dev/null +++ b/spring-kafka/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,17 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.spring.kafka.KafkaApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = KafkaApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} From 6f1e14b649b821cb1ab38c9ae3a3b3e24eb8d05d Mon Sep 17 00:00:00 2001 From: Andrey Shcherbakov Date: Sun, 6 Jan 2019 21:31:51 +0100 Subject: [PATCH 109/139] Code for article BAEL-2386 (#5958) * Add code for the article 'Java Primitives versus Objects' * Use JMH for benchmarking the primitive and wrapper classes * Uncomment the benchmarks and remove unused class * Add a binary search tree implementation * Add an example of how to use the binary tree class * Adjust the print statements * Add a code for article #BAEL-2386 --- .../flightrecorder/FlightRecorder.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java diff --git a/core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java b/core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java new file mode 100644 index 0000000000..02c3e96124 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java @@ -0,0 +1,32 @@ +package com.baeldung.flightrecorder; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple program that illustrates how to use Java Flight Recorder. + * + * This programs creates a list, inserts objects in it until + * an OutOfMemoryError is thrown. + * + */ +public class FlightRecorder { + + public static void main(String[] args) { + List items = new ArrayList<>(1); + try { + while (true) { + items.add(new Object()); + } + } catch (OutOfMemoryError e) { + System.out.println(e.getMessage()); + } + assert items.size() > 0; + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + } + } + +} From 65b9909fed4ab0a002cdb8554e0b86c91ae714a1 Mon Sep 17 00:00:00 2001 From: Rajesh Bhojwani Date: Mon, 7 Jan 2019 14:01:13 +0530 Subject: [PATCH 110/139] username:rajeshbhojwani "Java toString() method" (#6047) * Check in code for Java toString method * fix formatting issues * Fix formatting issues * Fix formatting issues * Fix formatting issues * Fix formatting issues * Fix formatting issues * replacing orders with order * Update formatting * Fix formatting * Fix formatting * Fix formatting * Fix formatting * Fix formatting --- .../baeldung/string/tostring/Customer.java | 19 ++++++++ .../tostring/CustomerArrayToString.java | 19 ++++++++ .../CustomerComplexObjectToString.java | 19 ++++++++ .../tostring/CustomerPrimitiveToString.java | 19 ++++++++ .../tostring/CustomerReflectionToString.java | 41 +++++++++++++++++ .../CustomerWrapperCollectionToString.java | 39 ++++++++++++++++ .../com/baeldung/string/tostring/Order.java | 46 +++++++++++++++++++ .../tostring/CustomerArrayToStringTest.java | 26 +++++++++++ .../CustomerComplexObjectToStringTest.java | 25 ++++++++++ .../CustomerPrimitiveToStringTest.java | 22 +++++++++ .../CustomerReflectionToStringTest.java | 32 +++++++++++++ ...CustomerWrapperCollectionToStringTest.java | 33 +++++++++++++ 12 files changed, 340 insertions(+) create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/Customer.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/CustomerArrayToString.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/CustomerComplexObjectToString.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/CustomerPrimitiveToString.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/CustomerReflectionToString.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/CustomerWrapperCollectionToString.java create mode 100644 java-strings/src/main/java/com/baeldung/string/tostring/Order.java create mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java create mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/Customer.java b/java-strings/src/main/java/com/baeldung/string/tostring/Customer.java new file mode 100644 index 0000000000..e914a83f0e --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/Customer.java @@ -0,0 +1,19 @@ +package com.baeldung.string.tostring; + +public class Customer { + private String firstName; + private String lastName; + + public String getFirstName() { + return firstName; + } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + public String getLastName() { + return lastName; + } + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/CustomerArrayToString.java b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerArrayToString.java new file mode 100644 index 0000000000..1736657276 --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerArrayToString.java @@ -0,0 +1,19 @@ +package com.baeldung.string.tostring; + +import java.util.Arrays; + +public class CustomerArrayToString extends Customer { + private Order[] orders; + + public Order[] getOrders() { + return orders; + } + public void setOrders(Order[] orders) { + this.orders = orders; + } + @Override + public String toString() { + return "Customer [orders=" + Arrays.toString(orders) + ", getFirstName()=" + getFirstName() + + ", getLastName()=" + getLastName() + "]"; + } +} diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/CustomerComplexObjectToString.java b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerComplexObjectToString.java new file mode 100644 index 0000000000..9bede1b3fc --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerComplexObjectToString.java @@ -0,0 +1,19 @@ +package com.baeldung.string.tostring; + +public class CustomerComplexObjectToString extends Customer { + private Order order; + + public Order getOrder() { + return order; + } + + public void setOrder(Order order) { + this.order = order; + } + + @Override + public String toString() { + return "Customer [order=" + order + ", getFirstName()=" + getFirstName() + + ", getLastName()=" + getLastName() + "]"; + } +} \ No newline at end of file diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/CustomerPrimitiveToString.java b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerPrimitiveToString.java new file mode 100644 index 0000000000..86e08ca447 --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerPrimitiveToString.java @@ -0,0 +1,19 @@ +package com.baeldung.string.tostring; + +public class CustomerPrimitiveToString extends Customer { + private long balance; + + public long getBalance() { + return balance; + } + + public void setBalance(long balance) { + this.balance = balance; + } + + @Override + public String toString() { + return "Customer [balance=" + balance + ", getFirstName()=" + getFirstName() + + ", getLastName()=" + getLastName() + "]"; + } +} diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/CustomerReflectionToString.java b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerReflectionToString.java new file mode 100644 index 0000000000..2da1163c63 --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerReflectionToString.java @@ -0,0 +1,41 @@ +package com.baeldung.string.tostring; + +import java.util.List; + +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; + +public class CustomerReflectionToString extends Customer{ + + private Integer score; + private List orders; + private StringBuffer fullname; + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + public List getOrders() { + return orders; + } + + public void setOrders(List orders) { + this.orders = orders; + } + + public StringBuffer getFullname() { + return fullname; + } + + public void setFullname(StringBuffer fullname) { + this.fullname = fullname; + } + + @Override + public String toString() { + return ReflectionToStringBuilder.toString(this); + } +} diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/CustomerWrapperCollectionToString.java b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerWrapperCollectionToString.java new file mode 100644 index 0000000000..6c7b999045 --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/CustomerWrapperCollectionToString.java @@ -0,0 +1,39 @@ +package com.baeldung.string.tostring; + +import java.util.List; + +public class CustomerWrapperCollectionToString extends Customer { + private Integer score; + private List orders; + private StringBuffer fullname; + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + public List getOrders() { + return orders; + } + + public void setOrders(List orders) { + this.orders = orders; + } + + public StringBuffer getFullname() { + return fullname; + } + + public void setFullname(StringBuffer fullname) { + this.fullname = fullname; + } + + @Override + public String toString() { + return "Customer [score=" + score + ", orders=" + orders + ", fullname=" + fullname + + ", getFirstName()=" + getFirstName() + ", getLastName()=" + getLastName() + "]"; + } +} diff --git a/java-strings/src/main/java/com/baeldung/string/tostring/Order.java b/java-strings/src/main/java/com/baeldung/string/tostring/Order.java new file mode 100644 index 0000000000..017e2d9bc8 --- /dev/null +++ b/java-strings/src/main/java/com/baeldung/string/tostring/Order.java @@ -0,0 +1,46 @@ +package com.baeldung.string.tostring; + +public class Order { + + private String orderId; + private String desc; + private long value; + private String status; + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + @Override + public String toString() { + return "Order [orderId=" + orderId + ", desc=" + desc + ", value=" + value + "]"; + } + +} diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java new file mode 100644 index 0000000000..31e268b4a3 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java @@ -0,0 +1,26 @@ +package com.baeldung.string.tostring; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class CustomerArrayToStringTest { + private static final String CUSTOMER_ARRAY_TO_STRING + = "Customer [orders=[Order [orderId=A1111, desc=Game, value=0]], getFirstName()=Rajesh, getLastName()=Bhojwani]"; + + @Test + public void givenArray_whenToString_thenCustomerDetails() { + CustomerArrayToString customer = new CustomerArrayToString(); + customer.setFirstName("Rajesh"); + customer.setLastName("Bhojwani"); + Order[] orders = new Order[1]; + orders[0] = new Order(); + orders[0].setOrderId("A1111"); + orders[0].setDesc("Game"); + orders[0].setStatus("In-Shiping"); + customer.setOrders(orders); + + assertEquals(CUSTOMER_ARRAY_TO_STRING, customer.toString()); + } + +} diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java new file mode 100644 index 0000000000..3c98394f85 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java @@ -0,0 +1,25 @@ +package com.baeldung.string.tostring; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class CustomerComplexObjectToStringTest { + private static final String CUSTOMER_COMPLEX_TO_STRING + = "Customer [order=Order [orderId=A1111, desc=Game, value=0], getFirstName()=Rajesh, getLastName()=Bhojwani]"; + + @Test + public void givenComplex_whenToString_thenCustomerDetails() { + CustomerComplexObjectToString customer = new CustomerComplexObjectToString(); + customer.setFirstName("Rajesh"); + customer.setLastName("Bhojwani"); + Order order = new Order(); + order.setOrderId("A1111"); + order.setDesc("Game"); + order.setStatus("In-Shiping"); + customer.setOrder(order); + + assertEquals(CUSTOMER_COMPLEX_TO_STRING, customer.toString()); + } + +} diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java new file mode 100644 index 0000000000..2a29cb93d8 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java @@ -0,0 +1,22 @@ +package com.baeldung.string.tostring; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class CustomerPrimitiveToStringTest { + + private static final String CUSTOMER_PRIMITIVE_TO_STRING + = "Customer [balance=110, getFirstName()=Rajesh, getLastName()=Bhojwani]"; + + @Test + public void givenPrimitive_whenToString_thenCustomerDetails() { + CustomerPrimitiveToString customer = new CustomerPrimitiveToString(); + customer.setFirstName("Rajesh"); + customer.setLastName("Bhojwani"); + customer.setBalance(110); + + assertEquals(CUSTOMER_PRIMITIVE_TO_STRING, customer.toString()); + } +} + diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java new file mode 100644 index 0000000000..290bef7133 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java @@ -0,0 +1,32 @@ +package com.baeldung.string.tostring; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class CustomerReflectionToStringTest { + private static final String CUSTOMER_REFLECTION_TO_STRING = "com.baeldung.string.tostring.CustomerReflectionToString"; + + @Test + public void givenWrapperCollectionStrBuffer_whenReflectionToString_thenCustomerDetails() { + CustomerReflectionToString customer = new CustomerReflectionToString(); + customer.setFirstName("Rajesh"); + customer.setLastName("Bhojwani"); + customer.setScore(8); + + List orders = new ArrayList(); + orders.add("Book"); + orders.add("Pen"); + customer.setOrders(orders); + + StringBuffer fullname = new StringBuffer(); + fullname.append(customer.getLastName()+", "+ customer.getFirstName()); + customer.setFullname(fullname); + + assertTrue(customer.toString().contains(CUSTOMER_REFLECTION_TO_STRING)); + } + +} diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java new file mode 100644 index 0000000000..c80969d453 --- /dev/null +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java @@ -0,0 +1,33 @@ +package com.baeldung.string.tostring; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class CustomerWrapperCollectionToStringTest { + private static final String CUSTOMER_WRAPPER_COLLECTION_TO_STRING + = "Customer [score=8, orders=[Book, Pen], fullname=Bhojwani, Rajesh, getFirstName()=Rajesh, getLastName()=Bhojwani]"; + + @Test + public void givenWrapperCollectionStrBuffer_whenToString_thenCustomerDetails() { + CustomerWrapperCollectionToString customer = new CustomerWrapperCollectionToString(); + customer.setFirstName("Rajesh"); + customer.setLastName("Bhojwani"); + customer.setScore(8); + + List orders = new ArrayList(); + orders.add("Book"); + orders.add("Pen"); + customer.setOrders(orders); + + StringBuffer fullname = new StringBuffer(); + fullname.append(customer.getLastName()+", "+ customer.getFirstName()); + customer.setFullname(fullname); + + assertEquals(CUSTOMER_WRAPPER_COLLECTION_TO_STRING, customer.toString()); + } + +} From 04743892db4547edada008b617ff6202da583da2 Mon Sep 17 00:00:00 2001 From: Alejandro Gervasio Date: Mon, 7 Jan 2019 08:17:52 -0300 Subject: [PATCH 111/139] What is thread-safety and how to achieve it Issue: BAEL-2416 --- .../threadsafety/application/Application.java | 86 +++++++++++++++++++ .../callables/AtomicCounterCallable.java | 19 ++++ .../callables/CounterCallable.java | 19 ++++ .../ExtrinsicLockCounterCallable.java | 19 ++++ .../callables/MessageServiceCallable.java | 19 ++++ .../ReentranReadWriteLockCounterCallable.java | 20 +++++ .../ReentrantLockCounterCallable.java | 19 ++++ .../threadsafety/mathutils/MathUtils.java | 14 +++ .../threadsafety/services/AtomicCounter.java | 18 ++++ .../threadsafety/services/Counter.java | 18 ++++ .../services/ExtrinsicLockCounter.java | 23 +++++ .../threadsafety/services/MessageService.java | 14 +++ .../services/ReentrantLockCounter.java | 26 ++++++ .../ReentrantReadWriteLockCounter.java | 34 ++++++++ .../threadsafety/services/StateHolder.java | 14 +++ .../threadsafety/tests/CounterTest.java | 23 +++++ .../tests/ExtrinsicLockCounterTest.java | 23 +++++ .../threadsafety/tests/MathUtilsTest.java | 13 +++ .../tests/MessageServiceTest.java | 23 +++++ .../tests/ReentrantLockCounterTest.java | 23 +++++ .../ReentrantReadWriteLockCounterTest.java | 24 ++++++ 21 files changed, 491 insertions(+) create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/application/Application.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/AtomicCounterCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/CounterCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ExtrinsicLockCounterCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/MessageServiceCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentranReadWriteLockCounterCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentrantLockCounterCallable.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/mathutils/MathUtils.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/AtomicCounter.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/Counter.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ExtrinsicLockCounter.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/MessageService.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantLockCounter.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantReadWriteLockCounter.java create mode 100644 core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/StateHolder.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/CounterTest.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ExtrinsicLockCounterTest.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MathUtilsTest.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MessageServiceTest.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantLockCounterTest.java create mode 100644 core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantReadWriteLockCounterTest.java diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/application/Application.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/application/Application.java new file mode 100644 index 0000000000..0c5caba8a0 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/application/Application.java @@ -0,0 +1,86 @@ +package com.baeldung.concurrent.threadsafety.application; + +import com.baeldung.concurrent.threadsafety.callables.AtomicCounterCallable; +import com.baeldung.concurrent.threadsafety.mathutils.MathUtils; +import com.baeldung.concurrent.threadsafety.callables.CounterCallable; +import com.baeldung.concurrent.threadsafety.callables.ExtrinsicLockCounterCallable; +import com.baeldung.concurrent.threadsafety.callables.MessageServiceCallable; +import com.baeldung.concurrent.threadsafety.callables.ReentranReadWriteLockCounterCallable; +import com.baeldung.concurrent.threadsafety.callables.ReentrantLockCounterCallable; +import com.baeldung.concurrent.threadsafety.services.AtomicCounter; +import com.baeldung.concurrent.threadsafety.services.Counter; +import com.baeldung.concurrent.threadsafety.services.ExtrinsicLockCounter; +import com.baeldung.concurrent.threadsafety.services.MessageService; +import com.baeldung.concurrent.threadsafety.services.ReentrantLockCounter; +import com.baeldung.concurrent.threadsafety.services.ReentrantReadWriteLockCounter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class Application { + + public static void main(String[] args) throws InterruptedException, ExecutionException { + + new Thread(() -> { + System.out.println(MathUtils.factorial(10)); + }).start(); + new Thread(() -> { + System.out.println(MathUtils.factorial(5)); + }).start(); + + ExecutorService executorService = Executors.newFixedThreadPool(10); + MessageService messageService = new MessageService("Welcome to Baeldung!"); + Future future1 = (Future) executorService.submit(new MessageServiceCallable(messageService)); + Future future2 = (Future) executorService.submit(new MessageServiceCallable(messageService)); + System.out.println(future1.get()); + System.out.println(future2.get()); + + Counter counter = new Counter(); + Future future3 = (Future) executorService.submit(new CounterCallable(counter)); + Future future4 = (Future) executorService.submit(new CounterCallable(counter)); + System.out.println(future3.get()); + System.out.println(future4.get()); + + ExtrinsicLockCounter extrinsicLockCounter = new ExtrinsicLockCounter(); + Future future5 = (Future) executorService.submit(new ExtrinsicLockCounterCallable(extrinsicLockCounter)); + Future future6 = (Future) executorService.submit(new ExtrinsicLockCounterCallable(extrinsicLockCounter)); + System.out.println(future5.get()); + System.out.println(future6.get()); + + ReentrantLockCounter reentrantLockCounter = new ReentrantLockCounter(); + Future future7 = (Future) executorService.submit(new ReentrantLockCounterCallable(reentrantLockCounter)); + Future future8 = (Future) executorService.submit(new ReentrantLockCounterCallable(reentrantLockCounter)); + System.out.println(future7.get()); + System.out.println(future8.get()); + + ReentrantReadWriteLockCounter reentrantReadWriteLockCounter = new ReentrantReadWriteLockCounter(); + Future future9 = (Future) executorService.submit(new ReentranReadWriteLockCounterCallable(reentrantReadWriteLockCounter)); + Future future10 = (Future) executorService.submit(new ReentranReadWriteLockCounterCallable(reentrantReadWriteLockCounter)); + System.out.println(future9.get()); + System.out.println(future10.get()); + + AtomicCounter atomicCounter = new AtomicCounter(); + Future future11 = (Future) executorService.submit(new AtomicCounterCallable(atomicCounter)); + Future future12 = (Future) executorService.submit(new AtomicCounterCallable(atomicCounter)); + System.out.println(future11.get()); + System.out.println(future12.get()); + + Collection syncCollection = Collections.synchronizedCollection(new ArrayList<>()); + Thread thread11 = new Thread(() -> syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6))); + Thread thread12 = new Thread(() -> syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6))); + thread11.start(); + thread12.start(); + + Map concurrentMap = new ConcurrentHashMap<>(); + concurrentMap.put("1", "one"); + concurrentMap.put("2", "two"); + concurrentMap.put("3", "three"); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/AtomicCounterCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/AtomicCounterCallable.java new file mode 100644 index 0000000000..d711299b5c --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/AtomicCounterCallable.java @@ -0,0 +1,19 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.AtomicCounter; +import java.util.concurrent.Callable; + +public class AtomicCounterCallable implements Callable { + + private final AtomicCounter counter; + + public AtomicCounterCallable(AtomicCounter counter) { + this.counter = counter; + } + + @Override + public Integer call() throws Exception { + counter.incrementCounter(); + return counter.getCounter(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/CounterCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/CounterCallable.java new file mode 100644 index 0000000000..cdcd84a17b --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/CounterCallable.java @@ -0,0 +1,19 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.Counter; +import java.util.concurrent.Callable; + +public class CounterCallable implements Callable { + + private final Counter counter; + + public CounterCallable(Counter counter) { + this.counter = counter; + } + + @Override + public Integer call() throws Exception { + counter.incrementCounter(); + return counter.getCounter(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ExtrinsicLockCounterCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ExtrinsicLockCounterCallable.java new file mode 100644 index 0000000000..29533e7630 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ExtrinsicLockCounterCallable.java @@ -0,0 +1,19 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.ExtrinsicLockCounter; +import java.util.concurrent.Callable; + +public class ExtrinsicLockCounterCallable implements Callable { + + private final ExtrinsicLockCounter counter; + + public ExtrinsicLockCounterCallable(ExtrinsicLockCounter counter) { + this.counter = counter; + } + + @Override + public Integer call() throws Exception { + counter.incrementCounter(); + return counter.getCounter(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/MessageServiceCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/MessageServiceCallable.java new file mode 100644 index 0000000000..84e8c7bb51 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/MessageServiceCallable.java @@ -0,0 +1,19 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.MessageService; +import java.util.concurrent.Callable; + +public class MessageServiceCallable implements Callable { + + private final MessageService messageService; + + public MessageServiceCallable(MessageService messageService) { + this.messageService = messageService; + + } + + @Override + public String call() { + return messageService.getMesssage(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentranReadWriteLockCounterCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentranReadWriteLockCounterCallable.java new file mode 100644 index 0000000000..e806460d50 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentranReadWriteLockCounterCallable.java @@ -0,0 +1,20 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.ReentrantReadWriteLockCounter; +import java.util.concurrent.Callable; + +public class ReentranReadWriteLockCounterCallable implements Callable { + + private final ReentrantReadWriteLockCounter counter; + + public ReentranReadWriteLockCounterCallable(ReentrantReadWriteLockCounter counter) { + this.counter = counter; + } + + @Override + public Integer call() throws Exception { + counter.incrementCounter(); + return counter.getCounter(); + } + +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentrantLockCounterCallable.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentrantLockCounterCallable.java new file mode 100644 index 0000000000..3511a98c60 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/callables/ReentrantLockCounterCallable.java @@ -0,0 +1,19 @@ +package com.baeldung.concurrent.threadsafety.callables; + +import com.baeldung.concurrent.threadsafety.services.ReentrantLockCounter; +import java.util.concurrent.Callable; + +public class ReentrantLockCounterCallable implements Callable { + + private final ReentrantLockCounter counter; + + public ReentrantLockCounterCallable(ReentrantLockCounter counter) { + this.counter = counter; + } + + @Override + public Integer call() throws Exception { + counter.incrementCounter(); + return counter.getCounter(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/mathutils/MathUtils.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/mathutils/MathUtils.java new file mode 100644 index 0000000000..f560cd4281 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/mathutils/MathUtils.java @@ -0,0 +1,14 @@ +package com.baeldung.concurrent.threadsafety.mathutils; + +import java.math.BigInteger; + +public class MathUtils { + + public static BigInteger factorial(int number) { + BigInteger f = new BigInteger("1"); + for (int i = 2; i <= number; i++) { + f = f.multiply(BigInteger.valueOf(i)); + } + return f; + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/AtomicCounter.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/AtomicCounter.java new file mode 100644 index 0000000000..32a373495c --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/AtomicCounter.java @@ -0,0 +1,18 @@ +package com.baeldung.concurrent.threadsafety.services; + +import java.util.concurrent.atomic.AtomicInteger; + +public class AtomicCounter { + + private final AtomicInteger counter = new AtomicInteger(); + + public AtomicCounter() {} + + public void incrementCounter() { + counter.incrementAndGet(); + } + + public synchronized int getCounter() { + return counter.get(); + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/Counter.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/Counter.java new file mode 100644 index 0000000000..f7dbc05639 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/Counter.java @@ -0,0 +1,18 @@ +package com.baeldung.concurrent.threadsafety.services; + +public class Counter { + + private volatile int counter; + + public Counter() { + this.counter = 0; + } + + public synchronized void incrementCounter() { + counter += 1; + } + + public int getCounter() { + return counter; + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ExtrinsicLockCounter.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ExtrinsicLockCounter.java new file mode 100644 index 0000000000..8ab431fbc3 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ExtrinsicLockCounter.java @@ -0,0 +1,23 @@ +package com.baeldung.concurrent.threadsafety.services; + +public class ExtrinsicLockCounter { + + private int counter; + private final Object lock = new Object(); + + public ExtrinsicLockCounter() { + this.counter = 0; + } + + public void incrementCounter() { + synchronized (lock) { + counter += 1; + } + } + + public int getCounter() { + synchronized (lock) { + return counter; + } + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/MessageService.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/MessageService.java new file mode 100644 index 0000000000..33981381ea --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/MessageService.java @@ -0,0 +1,14 @@ +package com.baeldung.concurrent.threadsafety.services; + +public class MessageService { + + private final String message; + + public MessageService(String message) { + this.message = message; + } + + public String getMesssage() { + return message; + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantLockCounter.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantLockCounter.java new file mode 100644 index 0000000000..717f0717af --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantLockCounter.java @@ -0,0 +1,26 @@ +package com.baeldung.concurrent.threadsafety.services; + +import java.util.concurrent.locks.ReentrantLock; + +public class ReentrantLockCounter { + + private int counter; + private final ReentrantLock reLock = new ReentrantLock(true); + + public ReentrantLockCounter() { + this.counter = 0; + } + + public void incrementCounter() { + reLock.lock(); + try { + counter += 1; + } finally { + reLock.unlock(); + } + } + + public int getCounter() { + return counter; + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantReadWriteLockCounter.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantReadWriteLockCounter.java new file mode 100644 index 0000000000..f740c938b1 --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/ReentrantReadWriteLockCounter.java @@ -0,0 +1,34 @@ +package com.baeldung.concurrent.threadsafety.services; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ReentrantReadWriteLockCounter { + + private int counter; + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); + + public ReentrantReadWriteLockCounter() { + this.counter = 0; + } + + public void incrementCounter() { + writeLock.lock(); + try { + counter += 1; + } finally { + writeLock.unlock(); + } + } + + public int getCounter() { + readLock.lock(); + try { + return counter; + } finally { + readLock.unlock(); + } + } +} diff --git a/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/StateHolder.java b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/StateHolder.java new file mode 100644 index 0000000000..5bbff9f39c --- /dev/null +++ b/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/threadsafety/services/StateHolder.java @@ -0,0 +1,14 @@ +package com.baeldung.concurrent.threadsafety.services; + +public class StateHolder { + + private final String state; + + public StateHolder(String state) { + this.state = state; + } + + public String getState() { + return state; + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/CounterTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/CounterTest.java new file mode 100644 index 0000000000..3abbb1bdad --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/CounterTest.java @@ -0,0 +1,23 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.concurrent.threadsafety.callables.CounterCallable; +import com.baeldung.concurrent.threadsafety.services.Counter; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class CounterTest { + + @Test + public void whenCalledIncrementCounter_thenCorrect() throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(2); + Counter counter = new Counter(); + Future future1 = (Future) executorService.submit(new CounterCallable(counter)); + Future future2 = (Future) executorService.submit(new CounterCallable(counter)); + + assertThat(future1.get()).isEqualTo(1); + assertThat(future2.get()).isEqualTo(2); + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ExtrinsicLockCounterTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ExtrinsicLockCounterTest.java new file mode 100644 index 0000000000..dba90f5b74 --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ExtrinsicLockCounterTest.java @@ -0,0 +1,23 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.concurrent.threadsafety.callables.ExtrinsicLockCounterCallable; +import com.baeldung.concurrent.threadsafety.services.ExtrinsicLockCounter; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class ExtrinsicLockCounterTest { + + @Test + public void whenCalledIncrementCounter_thenCorrect() throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(2); + ExtrinsicLockCounter counter = new ExtrinsicLockCounter(); + Future future1 = (Future) executorService.submit(new ExtrinsicLockCounterCallable(counter)); + Future future2 = (Future) executorService.submit(new ExtrinsicLockCounterCallable(counter)); + + assertThat(future1.get()).isEqualTo(1); + assertThat(future2.get()).isEqualTo(2); + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MathUtilsTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MathUtilsTest.java new file mode 100644 index 0000000000..8f3f574b03 --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MathUtilsTest.java @@ -0,0 +1,13 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import com.baeldung.concurrent.threadsafety.mathutils.MathUtils; +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class MathUtilsTest { + + @Test + public void whenCalledFactorialMethod_thenCorrect() { + assertThat(MathUtils.factorial(2)).isEqualTo(2); + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MessageServiceTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MessageServiceTest.java new file mode 100644 index 0000000000..8f1f1a8754 --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/MessageServiceTest.java @@ -0,0 +1,23 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.concurrent.threadsafety.callables.MessageServiceCallable; +import com.baeldung.concurrent.threadsafety.services.MessageService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class MessageServiceTest { + + @Test + public void whenCalledgetMessage_thenCorrect() throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(2); + MessageService messageService = new MessageService("Welcome to Baeldung!"); + Future future1 = (Future) executorService.submit(new MessageServiceCallable(messageService)); + Future future2 = (Future) executorService.submit(new MessageServiceCallable(messageService)); + + assertThat(future1.get()).isEqualTo("Welcome to Baeldung!"); + assertThat(future2.get()).isEqualTo("Welcome to Baeldung!"); + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantLockCounterTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantLockCounterTest.java new file mode 100644 index 0000000000..05c721ab26 --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantLockCounterTest.java @@ -0,0 +1,23 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import com.baeldung.concurrent.threadsafety.callables.ReentrantLockCounterCallable; +import com.baeldung.concurrent.threadsafety.services.ReentrantLockCounter; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class ReentrantLockCounterTest { + + @Test + public void whenCalledIncrementCounter_thenCorrect() throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(2); + ReentrantLockCounter counter = new ReentrantLockCounter(); + Future future1 = (Future) executorService.submit(new ReentrantLockCounterCallable(counter)); + Future future2 = (Future) executorService.submit(new ReentrantLockCounterCallable(counter)); + + assertThat(future1.get()).isEqualTo(1); + assertThat(future2.get()).isEqualTo(2); + } +} diff --git a/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantReadWriteLockCounterTest.java b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantReadWriteLockCounterTest.java new file mode 100644 index 0000000000..c56137ce04 --- /dev/null +++ b/core-java-concurrency-basic/src/test/com/baeldung/concurrent/threadsafety/tests/ReentrantReadWriteLockCounterTest.java @@ -0,0 +1,24 @@ +package com.baeldung.concurrent.threadsafety.tests; + +import com.baeldung.concurrent.threadsafety.callables.ReentranReadWriteLockCounterCallable; +import com.baeldung.concurrent.threadsafety.services.ReentrantReadWriteLockCounter; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class ReentrantReadWriteLockCounterTest { + + @Test + public void whenCalledIncrementCounter_thenCorrect() throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(2); + ReentrantReadWriteLockCounter counter = new ReentrantReadWriteLockCounter(); + Future future1 = (Future) executorService.submit(new ReentranReadWriteLockCounterCallable(counter)); + Future future2 = (Future) executorService.submit(new ReentranReadWriteLockCounterCallable(counter)); + + assertThat(future1.get()).isEqualTo(1); + assertThat(future2.get()).isEqualTo(2); + } + +} From 0e69cd5ab47d61ac4c18cac73e9d516e1c7ca8db Mon Sep 17 00:00:00 2001 From: Surapaneni Venkata Kiran Date: Mon, 7 Jan 2019 09:02:58 -0500 Subject: [PATCH 112/139] Changes to enable TLSv1.2 on Java 7 Issue: BAEL-2500 --- .../java/com/baeldung/ssl/EnableTLSv12.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 core-java-security/src/main/java/com/baeldung/ssl/EnableTLSv12.java diff --git a/core-java-security/src/main/java/com/baeldung/ssl/EnableTLSv12.java b/core-java-security/src/main/java/com/baeldung/ssl/EnableTLSv12.java new file mode 100644 index 0000000000..aa70b11584 --- /dev/null +++ b/core-java-security/src/main/java/com/baeldung/ssl/EnableTLSv12.java @@ -0,0 +1,115 @@ +package com.baeldung.ssl; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.URL; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EnableTLSv12 { + + private final Logger logger = LoggerFactory.getLogger(EnableTLSv12.class); + + public String url = ""; + public Integer port = null; + + public EnableTLSv12() { + } + + public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException { + EnableTLSv12 enableTLSv12 = new EnableTLSv12(); + if (args.length != 2) { + System.out.println("Provide the server url and the secure port:"); + System.exit(-1); + } + enableTLSv12.setHost(args); + enableTLSv12.setPort(args); + enableTLSv12.enableTLSv12UsingHttpConnection(); + enableTLSv12.enableTLSv12UsingProtocol(); + enableTLSv12.enableTLSv12UsingSSLContext(); + enableTLSv12.enableTLSv12UsingSSLParameters(); + } + + private void setPort(String[] args) { + url = args[0]; + } + + private void setHost(String[] args) { + String portNumber = args[1]; + port = Integer.parseInt(portNumber); + } + + private void handleCommunication(SSLSocket socket, String usedTLSProcess) throws IOException { + logger.debug("Enabled TLS v1.2 on " + usedTLSProcess); + try (PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { + out.println("GET / HTTP/1.0"); + out.println(); + out.flush(); + if (out.checkError()) { + logger.error("SSLSocketClient: java.io.PrintWriter error"); + return; + } + + String inputLine; + while ((inputLine = in.readLine()) != null) + logger.info(inputLine); + } + } + + public void enableTLSv12UsingSSLParameters() throws UnknownHostException, IOException { + SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(url.trim(), port); + SSLParameters params = new SSLParameters(); + params.setProtocols(new String[] { "TLSv1.2" }); + sslSocket.setSSLParameters(params); + sslSocket.startHandshake(); + handleCommunication(sslSocket, "SSLSocketFactory-SSLParameters"); + } + + public void enableTLSv12UsingProtocol() throws IOException { + SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(url, port); + sslSocket.setEnabledProtocols(new String[] { "TLSv1.2" }); + sslSocket.startHandshake(); + handleCommunication(sslSocket, "SSLSocketFactory-EnabledProtocols"); + } + + public void enableTLSv12UsingHttpConnection() throws IOException, NoSuchAlgorithmException, KeyManagementException { + URL urls = new URL("https://" + url + ":" + port); + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, null, new SecureRandom()); + HttpsURLConnection connection = (HttpsURLConnection) urls.openConnection(); + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String input; + while ((input = br.readLine()) != null) { + logger.info(input); + } + } + logger.debug("Created TLSv1.2 connection on HttpsURLConnection"); + } + + public void enableTLSv12UsingSSLContext() throws NoSuchAlgorithmException, KeyManagementException, UnknownHostException, IOException { + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, null, new SecureRandom()); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) socketFactory.createSocket(url, port); + handleCommunication(socket, "SSLContext"); + } + +} From 43b0770e134802ad328b6282c86af8ac2a729954 Mon Sep 17 00:00:00 2001 From: Emily Cheyne Date: Mon, 7 Jan 2019 18:36:15 -0700 Subject: [PATCH 113/139] Update readme (#6095) --- algorithms-miscellaneous-1/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms-miscellaneous-1/README.md b/algorithms-miscellaneous-1/README.md index 59765588b0..6f18396005 100644 --- a/algorithms-miscellaneous-1/README.md +++ b/algorithms-miscellaneous-1/README.md @@ -14,3 +14,4 @@ - [Calculate Factorial in Java](https://www.baeldung.com/java-calculate-factorial) - [Find Substrings That Are Palindromes in Java](https://www.baeldung.com/java-palindrome-substrings) - [Find the Longest Substring without Repeating Characters](https://www.baeldung.com/java-longest-substring-without-repeated-characters) +- [Java Two Pointer Technique](https://www.baeldung.com/java-two-pointer-technique) From ea1a4678929221680fcf15005ff9c1cfad775bae Mon Sep 17 00:00:00 2001 From: eric-martin Date: Mon, 7 Jan 2019 20:32:55 -0600 Subject: [PATCH 114/139] BAEL-2386: Moved FlightRecorder from core-java to core-java-perf --- .../src/main/java/com/baeldung/flightrecorder/FlightRecorder.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {core-java => core-java-perf}/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java (100%) diff --git a/core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java b/core-java-perf/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java similarity index 100% rename from core-java/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java rename to core-java-perf/src/main/java/com/baeldung/flightrecorder/FlightRecorder.java From 59fa72d45bdbed9936cd5e9e669f1c88bb5229a8 Mon Sep 17 00:00:00 2001 From: eric-martin Date: Mon, 7 Jan 2019 21:51:47 -0600 Subject: [PATCH 115/139] Fix PMD violations in java-strings *ToStringTest --- ...rrayToStringTest.java => CustomerArrayToStringUnitTest.java} | 2 +- ...ringTest.java => CustomerComplexObjectToStringUnitTest.java} | 2 +- ...ToStringTest.java => CustomerPrimitiveToStringUnitTest.java} | 2 +- ...oStringTest.java => CustomerReflectionToStringUnitTest.java} | 2 +- ...Test.java => CustomerWrapperCollectionToStringUnitTest.java} | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename java-strings/src/test/java/com/baeldung/string/tostring/{CustomerArrayToStringTest.java => CustomerArrayToStringUnitTest.java} (94%) rename java-strings/src/test/java/com/baeldung/string/tostring/{CustomerComplexObjectToStringTest.java => CustomerComplexObjectToStringUnitTest.java} (94%) rename java-strings/src/test/java/com/baeldung/string/tostring/{CustomerPrimitiveToStringTest.java => CustomerPrimitiveToStringUnitTest.java} (92%) rename java-strings/src/test/java/com/baeldung/string/tostring/{CustomerReflectionToStringTest.java => CustomerReflectionToStringUnitTest.java} (95%) rename java-strings/src/test/java/com/baeldung/string/tostring/{CustomerWrapperCollectionToStringTest.java => CustomerWrapperCollectionToStringUnitTest.java} (94%) diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringUnitTest.java similarity index 94% rename from java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java rename to java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringUnitTest.java index 31e268b4a3..9a88416179 100644 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringTest.java +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerArrayToStringUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class CustomerArrayToStringTest { +public class CustomerArrayToStringUnitTest { private static final String CUSTOMER_ARRAY_TO_STRING = "Customer [orders=[Order [orderId=A1111, desc=Game, value=0]], getFirstName()=Rajesh, getLastName()=Bhojwani]"; diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringUnitTest.java similarity index 94% rename from java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java rename to java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringUnitTest.java index 3c98394f85..5ffb0d0e58 100644 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringTest.java +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerComplexObjectToStringUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class CustomerComplexObjectToStringTest { +public class CustomerComplexObjectToStringUnitTest { private static final String CUSTOMER_COMPLEX_TO_STRING = "Customer [order=Order [orderId=A1111, desc=Game, value=0], getFirstName()=Rajesh, getLastName()=Bhojwani]"; diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringUnitTest.java similarity index 92% rename from java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java rename to java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringUnitTest.java index 2a29cb93d8..d43733bc60 100644 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringTest.java +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerPrimitiveToStringUnitTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -public class CustomerPrimitiveToStringTest { +public class CustomerPrimitiveToStringUnitTest { private static final String CUSTOMER_PRIMITIVE_TO_STRING = "Customer [balance=110, getFirstName()=Rajesh, getLastName()=Bhojwani]"; diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java similarity index 95% rename from java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java rename to java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java index 290bef7133..77dcab52e6 100644 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringTest.java +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java @@ -7,7 +7,7 @@ import java.util.List; import org.junit.jupiter.api.Test; -public class CustomerReflectionToStringTest { +public class CustomerReflectionToStringUnitTest { private static final String CUSTOMER_REFLECTION_TO_STRING = "com.baeldung.string.tostring.CustomerReflectionToString"; @Test diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringUnitTest.java similarity index 94% rename from java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java rename to java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringUnitTest.java index c80969d453..e04512ff75 100644 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringTest.java +++ b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerWrapperCollectionToStringUnitTest.java @@ -7,7 +7,7 @@ import java.util.List; import org.junit.jupiter.api.Test; -public class CustomerWrapperCollectionToStringTest { +public class CustomerWrapperCollectionToStringUnitTest { private static final String CUSTOMER_WRAPPER_COLLECTION_TO_STRING = "Customer [score=8, orders=[Book, Pen], fullname=Bhojwani, Rajesh, getFirstName()=Rajesh, getLastName()=Bhojwani]"; From ffcb8f586625f20ada94658ebeba6cd92e965b80 Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Tue, 8 Jan 2019 10:44:18 +0000 Subject: [PATCH 116/139] Kovert (#6092) * Kovert examples * Moved the Kovert examples to kotlin-libraries --- kotlin-libraries/pom.xml | 19 ++++- .../com/baeldung/kovert/AnnotatedServer.kt | 73 ++++++++++++++++++ .../kotlin/com/baeldung/kovert/ErrorServer.kt | 75 ++++++++++++++++++ .../kotlin/com/baeldung/kovert/JsonServer.kt | 76 +++++++++++++++++++ .../kotlin/com/baeldung/kovert/NoopServer.kt | 57 ++++++++++++++ .../com/baeldung/kovert/SecuredServer.kt | 68 +++++++++++++++++ .../com/baeldung/kovert/SimpleServer.kt | 65 ++++++++++++++++ .../src/main/resources/kovert.conf | 15 ++++ 8 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/JsonServer.kt create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/NoopServer.kt create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt create mode 100644 kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt create mode 100644 kotlin-libraries/src/main/resources/kovert.conf diff --git a/kotlin-libraries/pom.xml b/kotlin-libraries/pom.xml index ae77a9aa2d..507e5820d4 100644 --- a/kotlin-libraries/pom.xml +++ b/kotlin-libraries/pom.xml @@ -95,6 +95,23 @@ 0.7.3 + + uy.kohesive.kovert + kovert-vertx + [1.5.0,1.6.0) + + + nl.komponents.kovenant + kovenant + + + + + nl.komponents.kovenant + kovenant + 3.3.0 + pom + @@ -110,4 +127,4 @@ 0.10.4 - \ No newline at end of file + diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt new file mode 100644 index 0000000000..da2bbe4208 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt @@ -0,0 +1,73 @@ +package com.baeldung.kovert + +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.core.HttpVerb +import uy.kohesive.kovert.core.Location +import uy.kohesive.kovert.core.Verb +import uy.kohesive.kovert.core.VerbAlias +import uy.kohesive.kovert.vertx.bindController +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + + +class AnnotatedServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(AnnotatedServer::class.java) + + @JvmStatic + fun main(args: Array) { + AnnotatedServer().start() + } + } + + @VerbAlias("show", HttpVerb.GET) + class AnnotatedController { + fun RoutingContext.showStringById(id: String) = id + + @Verb(HttpVerb.GET) + @Location("/ping/:id") + fun RoutingContext.ping(id: String) = id + } + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", AnnotatedServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + bindController(AnnotatedController(), "api") + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt new file mode 100644 index 0000000000..a596391ed8 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt @@ -0,0 +1,75 @@ +package com.baeldung.kovert + +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.core.HttpErrorCode +import uy.kohesive.kovert.core.HttpErrorCodeWithBody +import uy.kohesive.kovert.core.HttpErrorForbidden +import uy.kohesive.kovert.vertx.bindController +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + + +class ErrorServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(ErrorServer::class.java) + + @JvmStatic + fun main(args: Array) { + ErrorServer().start() + } + } + + class ErrorController { + fun RoutingContext.getForbidden() { + throw HttpErrorForbidden() + } + fun RoutingContext.getError() { + throw HttpErrorCode("Something went wrong", 590) + } + fun RoutingContext.getErrorbody() { + throw HttpErrorCodeWithBody("Something went wrong", 591, "Body here") + } + } + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", ErrorServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + bindController(ErrorController(), "api") + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/JsonServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/JsonServer.kt new file mode 100644 index 0000000000..310fe2a7a0 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/JsonServer.kt @@ -0,0 +1,76 @@ +package com.baeldung.kovert + +import com.fasterxml.jackson.annotation.JsonProperty +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.vertx.bindController +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + +class JsonServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(JsonServer::class.java) + + @JvmStatic + fun main(args: Array) { + JsonServer().start() + } + } + + data class Person( + @JsonProperty("_id") + val id: String, + val name: String, + val job: String + ) + + class JsonController { + fun RoutingContext.getPersonById(id: String) = Person( + id = id, + name = "Tony Stark", + job = "Iron Man" + ) + fun RoutingContext.putPersonById(id: String, person: Person) = person + } + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", JsonServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + bindController(JsonController(), "api") + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/NoopServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/NoopServer.kt new file mode 100644 index 0000000000..98ce775e66 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/NoopServer.kt @@ -0,0 +1,57 @@ +package com.baeldung.kovert + +import io.vertx.ext.web.Router +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + +class NoopServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(NoopServer::class.java) + + @JvmStatic + fun main(args: Array) { + NoopServer().start() + } + } + + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", NoopServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt new file mode 100644 index 0000000000..86ca482808 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt @@ -0,0 +1,68 @@ +package com.baeldung.kovert + +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.vertx.bindController +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + + +class SecuredServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(SecuredServer::class.java) + + @JvmStatic + fun main(args: Array) { + SecuredServer().start() + } + } + + class SecuredContext(private val routingContext: RoutingContext) { + val authenticated = routingContext.request().getHeader("Authorization") == "Secure" + } + + class SecuredController { + fun SecuredContext.getSecured() = this.authenticated + } + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", SecuredServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + bindController(SecuredController(), "api") + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt new file mode 100644 index 0000000000..172469ab46 --- /dev/null +++ b/kotlin-libraries/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt @@ -0,0 +1,65 @@ +package com.baeldung.kovert + +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import nl.komponents.kovenant.functional.bind +import org.kodein.di.Kodein +import org.kodein.di.conf.global +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import uy.klutter.config.typesafe.ClassResourceConfig +import uy.klutter.config.typesafe.ReferenceConfig +import uy.klutter.config.typesafe.kodein.importConfig +import uy.klutter.config.typesafe.loadConfig +import uy.klutter.vertx.kodein.KodeinVertx +import uy.kohesive.kovert.vertx.bindController +import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx +import uy.kohesive.kovert.vertx.boot.KovertVerticle +import uy.kohesive.kovert.vertx.boot.KovertVerticleModule +import uy.kohesive.kovert.vertx.boot.KovertVertx + + +class SimpleServer { + companion object { + private val LOG: Logger = LoggerFactory.getLogger(SimpleServer::class.java) + + @JvmStatic + fun main(args: Array) { + SimpleServer().start() + } + } + + class SimpleController { + fun RoutingContext.getStringById(id: String) = id + fun RoutingContext.get_truncatedString_by_id(id: String, length: Int = 1) = id.subSequence(0, length) + } + + fun start() { + Kodein.global.addImport(Kodein.Module { + importConfig(loadConfig(ClassResourceConfig("/kovert.conf", SimpleServer::class.java), ReferenceConfig())) { + import("kovert.vertx", KodeinKovertVertx.configModule) + import("kovert.server", KovertVerticleModule.configModule) + } + + // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j + import(KodeinVertx.moduleWithLoggingToSlf4j) + // Kovert boot + import(KodeinKovertVertx.module) + import(KovertVerticleModule.module) + }) + + val initControllers = fun Router.() { + bindController(SimpleController(), "api") + } + + // startup asynchronously... + KovertVertx.start() bind { vertx -> + KovertVerticle.deploy(vertx, routerInit = initControllers) + } success { deploymentId -> + LOG.warn("Deployment complete.") + } fail { error -> + LOG.error("Deployment failed!", error) + } + + } +} diff --git a/kotlin-libraries/src/main/resources/kovert.conf b/kotlin-libraries/src/main/resources/kovert.conf new file mode 100644 index 0000000000..3b08641693 --- /dev/null +++ b/kotlin-libraries/src/main/resources/kovert.conf @@ -0,0 +1,15 @@ +{ + kovert: { + vertx: { + clustered: false + } + server: { + listeners: [ + { + host: "0.0.0.0" + port: "8000" + } + ] + } + } +} From 802e2b0398f46f9939308416066fe9bfe0bf3c6c Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Tue, 8 Jan 2019 14:06:25 +0000 Subject: [PATCH 117/139] Removed Kovert from core-kotlin now it's in kotlin-libraries instead (#6101) --- core-kotlin/pom.xml | 11 --- .../com/baeldung/kovert/AnnotatedServer.kt | 73 ------------------ .../kotlin/com/baeldung/kovert/ErrorServer.kt | 75 ------------------ .../kotlin/com/baeldung/kovert/JsonServer.kt | 76 ------------------- .../kotlin/com/baeldung/kovert/NoopServer.kt | 57 -------------- .../com/baeldung/kovert/SecuredServer.kt | 68 ----------------- .../com/baeldung/kovert/SimpleServer.kt | 65 ---------------- core-kotlin/src/main/resources/kovert.conf | 15 ---- 8 files changed, 440 deletions(-) delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/JsonServer.kt delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/NoopServer.kt delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt delete mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt delete mode 100644 core-kotlin/src/main/resources/kovert.conf diff --git a/core-kotlin/pom.xml b/core-kotlin/pom.xml index 8b871f28ee..ed79ebc01b 100644 --- a/core-kotlin/pom.xml +++ b/core-kotlin/pom.xml @@ -72,17 +72,6 @@ injekt-core 1.16.1 - - uy.kohesive.kovert - kovert-vertx - [1.5.0,1.6.0) - - - nl.komponents.kovenant - kovenant - - - diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt deleted file mode 100644 index da2bbe4208..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/AnnotatedServer.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.baeldung.kovert - -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.core.HttpVerb -import uy.kohesive.kovert.core.Location -import uy.kohesive.kovert.core.Verb -import uy.kohesive.kovert.core.VerbAlias -import uy.kohesive.kovert.vertx.bindController -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - - -class AnnotatedServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(AnnotatedServer::class.java) - - @JvmStatic - fun main(args: Array) { - AnnotatedServer().start() - } - } - - @VerbAlias("show", HttpVerb.GET) - class AnnotatedController { - fun RoutingContext.showStringById(id: String) = id - - @Verb(HttpVerb.GET) - @Location("/ping/:id") - fun RoutingContext.ping(id: String) = id - } - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", AnnotatedServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - bindController(AnnotatedController(), "api") - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt deleted file mode 100644 index a596391ed8..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/ErrorServer.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.baeldung.kovert - -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.core.HttpErrorCode -import uy.kohesive.kovert.core.HttpErrorCodeWithBody -import uy.kohesive.kovert.core.HttpErrorForbidden -import uy.kohesive.kovert.vertx.bindController -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - - -class ErrorServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(ErrorServer::class.java) - - @JvmStatic - fun main(args: Array) { - ErrorServer().start() - } - } - - class ErrorController { - fun RoutingContext.getForbidden() { - throw HttpErrorForbidden() - } - fun RoutingContext.getError() { - throw HttpErrorCode("Something went wrong", 590) - } - fun RoutingContext.getErrorbody() { - throw HttpErrorCodeWithBody("Something went wrong", 591, "Body here") - } - } - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", ErrorServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - bindController(ErrorController(), "api") - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/JsonServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/JsonServer.kt deleted file mode 100644 index 310fe2a7a0..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/JsonServer.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.baeldung.kovert - -import com.fasterxml.jackson.annotation.JsonProperty -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.vertx.bindController -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - -class JsonServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(JsonServer::class.java) - - @JvmStatic - fun main(args: Array) { - JsonServer().start() - } - } - - data class Person( - @JsonProperty("_id") - val id: String, - val name: String, - val job: String - ) - - class JsonController { - fun RoutingContext.getPersonById(id: String) = Person( - id = id, - name = "Tony Stark", - job = "Iron Man" - ) - fun RoutingContext.putPersonById(id: String, person: Person) = person - } - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", JsonServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - bindController(JsonController(), "api") - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/NoopServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/NoopServer.kt deleted file mode 100644 index 98ce775e66..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/NoopServer.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.baeldung.kovert - -import io.vertx.ext.web.Router -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - -class NoopServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(NoopServer::class.java) - - @JvmStatic - fun main(args: Array) { - NoopServer().start() - } - } - - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", NoopServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt deleted file mode 100644 index 86ca482808..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/SecuredServer.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.baeldung.kovert - -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.vertx.bindController -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - - -class SecuredServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(SecuredServer::class.java) - - @JvmStatic - fun main(args: Array) { - SecuredServer().start() - } - } - - class SecuredContext(private val routingContext: RoutingContext) { - val authenticated = routingContext.request().getHeader("Authorization") == "Secure" - } - - class SecuredController { - fun SecuredContext.getSecured() = this.authenticated - } - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", SecuredServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - bindController(SecuredController(), "api") - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt b/core-kotlin/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt deleted file mode 100644 index 172469ab46..0000000000 --- a/core-kotlin/src/main/kotlin/com/baeldung/kovert/SimpleServer.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.baeldung.kovert - -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import nl.komponents.kovenant.functional.bind -import org.kodein.di.Kodein -import org.kodein.di.conf.global -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import uy.klutter.config.typesafe.ClassResourceConfig -import uy.klutter.config.typesafe.ReferenceConfig -import uy.klutter.config.typesafe.kodein.importConfig -import uy.klutter.config.typesafe.loadConfig -import uy.klutter.vertx.kodein.KodeinVertx -import uy.kohesive.kovert.vertx.bindController -import uy.kohesive.kovert.vertx.boot.KodeinKovertVertx -import uy.kohesive.kovert.vertx.boot.KovertVerticle -import uy.kohesive.kovert.vertx.boot.KovertVerticleModule -import uy.kohesive.kovert.vertx.boot.KovertVertx - - -class SimpleServer { - companion object { - private val LOG: Logger = LoggerFactory.getLogger(SimpleServer::class.java) - - @JvmStatic - fun main(args: Array) { - SimpleServer().start() - } - } - - class SimpleController { - fun RoutingContext.getStringById(id: String) = id - fun RoutingContext.get_truncatedString_by_id(id: String, length: Int = 1) = id.subSequence(0, length) - } - - fun start() { - Kodein.global.addImport(Kodein.Module { - importConfig(loadConfig(ClassResourceConfig("/kovert.conf", SimpleServer::class.java), ReferenceConfig())) { - import("kovert.vertx", KodeinKovertVertx.configModule) - import("kovert.server", KovertVerticleModule.configModule) - } - - // includes jackson ObjectMapper to match compatibility with Vertx, app logging via Vertx facade to Slf4j - import(KodeinVertx.moduleWithLoggingToSlf4j) - // Kovert boot - import(KodeinKovertVertx.module) - import(KovertVerticleModule.module) - }) - - val initControllers = fun Router.() { - bindController(SimpleController(), "api") - } - - // startup asynchronously... - KovertVertx.start() bind { vertx -> - KovertVerticle.deploy(vertx, routerInit = initControllers) - } success { deploymentId -> - LOG.warn("Deployment complete.") - } fail { error -> - LOG.error("Deployment failed!", error) - } - - } -} diff --git a/core-kotlin/src/main/resources/kovert.conf b/core-kotlin/src/main/resources/kovert.conf deleted file mode 100644 index 3b08641693..0000000000 --- a/core-kotlin/src/main/resources/kovert.conf +++ /dev/null @@ -1,15 +0,0 @@ -{ - kovert: { - vertx: { - clustered: false - } - server: { - listeners: [ - { - host: "0.0.0.0" - port: "8000" - } - ] - } - } -} From 5faa406cb062ae194f84a19ab029eb5176ecbcb4 Mon Sep 17 00:00:00 2001 From: myluckagain Date: Tue, 8 Jan 2019 19:36:42 +0500 Subject: [PATCH 118/139] BAEL-2474 (#5997) * BAEL-2474 * rename UserRepositoryImpl.java into UserRepositoryCustomImpl.java --- .../dao/repositories/user/UserRepository.java | 3 +- .../user/UserRepositoryCustom.java | 10 ++++ .../user/UserRepositoryCustomImpl.java | 43 +++++++++++++++ .../UserRepositoryIntegrationTest.java | 55 +++++++++++++------ 4 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java create mode 100644 persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java index 5bb0232e4a..7f54254832 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepository.java @@ -1,6 +1,7 @@ package com.baeldung.dao.repositories.user; import com.baeldung.domain.user.User; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -13,7 +14,7 @@ import java.util.Collection; import java.util.List; import java.util.stream.Stream; -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository , UserRepositoryCustom{ Stream findAllByName(String name); diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java new file mode 100644 index 0000000000..72c1fd5d00 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.baeldung.dao.repositories.user; + +import java.util.List; +import java.util.Set; + +import com.baeldung.domain.user.User; + +public interface UserRepositoryCustom { + List findUserByEmails(Set emails); +} diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java new file mode 100644 index 0000000000..9f841caf68 --- /dev/null +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/dao/repositories/user/UserRepositoryCustomImpl.java @@ -0,0 +1,43 @@ +package com.baeldung.dao.repositories.user; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import com.baeldung.domain.user.User; + +public class UserRepositoryCustomImpl implements UserRepositoryCustom { + + @PersistenceContext + private EntityManager entityManager; + + @Override + public List findUserByEmails(Set emails) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(User.class); + Root user = query.from(User.class); + + Path emailPath = user.get("email"); + + List predicates = new ArrayList<>(); + for (String email : emails) { + + predicates.add(cb.like(emailPath, email)); + + } + query.select(user) + .where(cb.or(predicates.toArray(new Predicate[predicates.size()]))); + + return entityManager.createQuery(query) + .getResultList(); + } + +} diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java index e29161394b..b05086d00e 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/dao/repositories/UserRepositoryIntegrationTest.java @@ -18,7 +18,9 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; @@ -274,9 +276,8 @@ public class UserRepositoryIntegrationTest { List usersSortByName = userRepository.findAll(new Sort(Sort.Direction.ASC, "name")); - assertThat(usersSortByName - .get(0) - .getName()).isEqualTo(USER_NAME_ADAM); + assertThat(usersSortByName.get(0) + .getName()).isEqualTo(USER_NAME_ADAM); } @Test(expected = PropertyReferenceException.class) @@ -289,9 +290,8 @@ public class UserRepositoryIntegrationTest { List usersSortByNameLength = userRepository.findAll(new Sort("LENGTH(name)")); - assertThat(usersSortByNameLength - .get(0) - .getName()).isEqualTo(USER_NAME_ADAM); + assertThat(usersSortByNameLength.get(0) + .getName()).isEqualTo(USER_NAME_ADAM); } @Test @@ -304,9 +304,8 @@ public class UserRepositoryIntegrationTest { List usersSortByNameLength = userRepository.findAllUsers(JpaSort.unsafe("LENGTH(name)")); - assertThat(usersSortByNameLength - .get(0) - .getName()).isEqualTo(USER_NAME_ADAM); + assertThat(usersSortByNameLength.get(0) + .getName()).isEqualTo(USER_NAME_ADAM); } @Test @@ -320,10 +319,9 @@ public class UserRepositoryIntegrationTest { Page usersPage = userRepository.findAllUsersWithPagination(new PageRequest(1, 3)); - assertThat(usersPage - .getContent() - .get(0) - .getName()).isEqualTo("SAMPLE1"); + assertThat(usersPage.getContent() + .get(0) + .getName()).isEqualTo("SAMPLE1"); } @Test @@ -337,10 +335,9 @@ public class UserRepositoryIntegrationTest { Page usersSortByNameLength = userRepository.findAllUsersWithPaginationNative(new PageRequest(1, 3)); - assertThat(usersSortByNameLength - .getContent() - .get(0) - .getName()).isEqualTo("SAMPLE1"); + assertThat(usersSortByNameLength.getContent() + .get(0) + .getName()).isEqualTo("SAMPLE1"); } @Test @@ -370,6 +367,30 @@ public class UserRepositoryIntegrationTest { assertThat(updatedUsersSize).isEqualTo(2); } + @Test + public void givenUsersInDBWhenFindByEmailsWithDynamicQueryThenReturnCollection() { + + User user1 = new User(); + user1.setEmail(USER_EMAIL); + userRepository.save(user1); + + User user2 = new User(); + user2.setEmail(USER_EMAIL2); + userRepository.save(user2); + + User user3 = new User(); + user3.setEmail(USER_EMAIL3); + userRepository.save(user3); + + Set emails = new HashSet<>(); + emails.add(USER_EMAIL2); + emails.add(USER_EMAIL3); + + Collection usersWithEmails = userRepository.findUserByEmails(emails); + + assertThat(usersWithEmails.size()).isEqualTo(2); + } + @After public void cleanUp() { userRepository.deleteAll(); From f1fa9c8253a9db826ad4de40dd71be2ec2ac7527 Mon Sep 17 00:00:00 2001 From: pandachris Date: Tue, 8 Jan 2019 22:18:47 +0700 Subject: [PATCH 119/139] BAEL-2565 move code to different project (#6099) * BAEL-2565 * BAEL-2565 Test code consistency * BAEL-2565 Move code to different project --- .../src/main/java/com/baeldung/enums/values/Element1.java | 0 .../src/main/java/com/baeldung/enums/values/Element2.java | 0 .../src/main/java/com/baeldung/enums/values/Element3.java | 0 .../src/main/java/com/baeldung/enums/values/Element4.java | 0 .../src/main/java/com/baeldung/enums/values/Labeled.java | 0 .../src/test/java/com/baeldung/enums/values/Element1UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element2UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element3UnitTest.java | 0 .../src/test/java/com/baeldung/enums/values/Element4UnitTest.java | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename {core-java-8 => core-java-lang}/src/main/java/com/baeldung/enums/values/Element1.java (100%) rename {core-java-8 => core-java-lang}/src/main/java/com/baeldung/enums/values/Element2.java (100%) rename {core-java-8 => core-java-lang}/src/main/java/com/baeldung/enums/values/Element3.java (100%) rename {core-java-8 => core-java-lang}/src/main/java/com/baeldung/enums/values/Element4.java (100%) rename {core-java-8 => core-java-lang}/src/main/java/com/baeldung/enums/values/Labeled.java (100%) rename {core-java-8 => core-java-lang}/src/test/java/com/baeldung/enums/values/Element1UnitTest.java (100%) rename {core-java-8 => core-java-lang}/src/test/java/com/baeldung/enums/values/Element2UnitTest.java (100%) rename {core-java-8 => core-java-lang}/src/test/java/com/baeldung/enums/values/Element3UnitTest.java (100%) rename {core-java-8 => core-java-lang}/src/test/java/com/baeldung/enums/values/Element4UnitTest.java (100%) diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element1.java b/core-java-lang/src/main/java/com/baeldung/enums/values/Element1.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/enums/values/Element1.java rename to core-java-lang/src/main/java/com/baeldung/enums/values/Element1.java diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element2.java b/core-java-lang/src/main/java/com/baeldung/enums/values/Element2.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/enums/values/Element2.java rename to core-java-lang/src/main/java/com/baeldung/enums/values/Element2.java diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element3.java b/core-java-lang/src/main/java/com/baeldung/enums/values/Element3.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/enums/values/Element3.java rename to core-java-lang/src/main/java/com/baeldung/enums/values/Element3.java diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Element4.java b/core-java-lang/src/main/java/com/baeldung/enums/values/Element4.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/enums/values/Element4.java rename to core-java-lang/src/main/java/com/baeldung/enums/values/Element4.java diff --git a/core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java b/core-java-lang/src/main/java/com/baeldung/enums/values/Labeled.java similarity index 100% rename from core-java-8/src/main/java/com/baeldung/enums/values/Labeled.java rename to core-java-lang/src/main/java/com/baeldung/enums/values/Labeled.java diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java b/core-java-lang/src/test/java/com/baeldung/enums/values/Element1UnitTest.java similarity index 100% rename from core-java-8/src/test/java/com/baeldung/enums/values/Element1UnitTest.java rename to core-java-lang/src/test/java/com/baeldung/enums/values/Element1UnitTest.java diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java b/core-java-lang/src/test/java/com/baeldung/enums/values/Element2UnitTest.java similarity index 100% rename from core-java-8/src/test/java/com/baeldung/enums/values/Element2UnitTest.java rename to core-java-lang/src/test/java/com/baeldung/enums/values/Element2UnitTest.java diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java b/core-java-lang/src/test/java/com/baeldung/enums/values/Element3UnitTest.java similarity index 100% rename from core-java-8/src/test/java/com/baeldung/enums/values/Element3UnitTest.java rename to core-java-lang/src/test/java/com/baeldung/enums/values/Element3UnitTest.java diff --git a/core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java b/core-java-lang/src/test/java/com/baeldung/enums/values/Element4UnitTest.java similarity index 100% rename from core-java-8/src/test/java/com/baeldung/enums/values/Element4UnitTest.java rename to core-java-lang/src/test/java/com/baeldung/enums/values/Element4UnitTest.java From c0e36d5b10ca8716390ac1954218b037e9775b83 Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Wed, 9 Jan 2019 00:30:54 +0530 Subject: [PATCH 120/139] BAEL-10925 New module spring-boot-rest --- pom.xml | 6 ++- spring-boot-rest/pom.xml | 43 +++++++++++++++++++ .../web/SpringBootRestApplication.java | 13 ++++++ .../com/baeldung/web/config/WebConfig.java | 8 ++++ .../src/main/resources/application.properties | 0 .../SpringBootRestApplicationUnitTest.java | 16 +++++++ 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 spring-boot-rest/pom.xml create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java create mode 100644 spring-boot-rest/src/main/resources/application.properties create mode 100644 spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java diff --git a/pom.xml b/pom.xml index 4dba0da173..cf7eb1f394 100644 --- a/pom.xml +++ b/pom.xml @@ -645,6 +645,7 @@ spring-boot-mvc spring-boot-ops spring-boot-property-exp + spring-boot-rest spring-boot-security spring-boot-testing spring-boot-vue @@ -1356,8 +1357,11 @@ spring-boot-mvc spring-boot-ops spring-boot-property-exp + spring-boot-rest spring-boot-security + spring-boot-testing spring-boot-vue + spring-boot-libraries spring-cloud spring-cloud-bus @@ -1372,7 +1376,7 @@ spring-dispatcher-servlet spring-drools - spring-ehcache + spring-ehcache spring-ejb spring-exceptions diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml new file mode 100644 index 0000000000..baf9d35a09 --- /dev/null +++ b/spring-boot-rest/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + com.baeldung.web + spring-boot-rest + spring-boot-rest + Spring Boot Rest Module + war + + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + com.baeldung.SpringBootRestApplication + + diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java b/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java new file mode 100644 index 0000000000..62aae7619d --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootRestApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootRestApplication.class, args); + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java new file mode 100644 index 0000000000..808e946218 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java @@ -0,0 +1,8 @@ +package com.baeldung.web.config; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class WebConfig { + +} \ No newline at end of file diff --git a/spring-boot-rest/src/main/resources/application.properties b/spring-boot-rest/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java new file mode 100644 index 0000000000..747e08f6f8 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.boot.rest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringBootRestApplicationUnitTest { + + @Test + public void contextLoads() { + } + +} From 842d8573af8bef74a34b3b65d3f7bae59ffa5742 Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Wed, 9 Jan 2019 00:38:14 +0530 Subject: [PATCH 121/139] Revert parent pom.xml --- pom.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index cf7eb1f394..4dba0da173 100644 --- a/pom.xml +++ b/pom.xml @@ -645,7 +645,6 @@ spring-boot-mvc spring-boot-ops spring-boot-property-exp - spring-boot-rest spring-boot-security spring-boot-testing spring-boot-vue @@ -1357,11 +1356,8 @@ spring-boot-mvc spring-boot-ops spring-boot-property-exp - spring-boot-rest spring-boot-security - spring-boot-testing spring-boot-vue - spring-boot-libraries spring-cloud spring-cloud-bus @@ -1376,7 +1372,7 @@ spring-dispatcher-servlet spring-drools - spring-ehcache + spring-ehcache spring-ejb spring-exceptions From 6cd561d91a1ef1d8b5fc52f2d10ceff16e4bcf1f Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Wed, 9 Jan 2019 00:41:57 +0530 Subject: [PATCH 122/139] Fixed pom.xml --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index 4dba0da173..324f6129db 100644 --- a/pom.xml +++ b/pom.xml @@ -644,6 +644,7 @@ spring-boot-logging-log4j2 spring-boot-mvc spring-boot-ops + spring-boot-rest spring-boot-property-exp spring-boot-security spring-boot-testing @@ -1355,6 +1356,7 @@ spring-boot-logging-log4j2 spring-boot-mvc spring-boot-ops + spring-boot-rest spring-boot-property-exp spring-boot-security spring-boot-vue From e6f28c61a3484d5cd488c1160981ac36c35e8b05 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 9 Jan 2019 00:09:02 +0200 Subject: [PATCH 123/139] Create README.md --- spring-boot-rest/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 spring-boot-rest/README.md diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md new file mode 100644 index 0000000000..0a8d13cf76 --- /dev/null +++ b/spring-boot-rest/README.md @@ -0,0 +1,3 @@ +Module for the articles that are part of the Spring REST E-book: + +1. [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) From 58ed9e47b204652bae2ced49cb0b541840272f8f Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Wed, 9 Jan 2019 00:12:40 +0200 Subject: [PATCH 124/139] Update and rename SpringBootRestApplicationUnitTest.java to SpringContextIntegrationTest.java --- ...plicationUnitTest.java => SpringContextIntegrationTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename spring-boot-rest/src/test/java/com/baeldung/web/{SpringBootRestApplicationUnitTest.java => SpringContextIntegrationTest.java} (86%) diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java similarity index 86% rename from spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java rename to spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java index 747e08f6f8..0c1fdf372b 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/SpringBootRestApplicationUnitTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java @@ -7,7 +7,7 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest -public class SpringBootRestApplicationUnitTest { +public class SpringContextIntegrationTest { @Test public void contextLoads() { From 44490a052ff0760b5115ba5764e53553c41ccf44 Mon Sep 17 00:00:00 2001 From: Sam Millington Date: Wed, 9 Jan 2019 18:06:47 +0000 Subject: [PATCH 125/139] BAEL2526 queue interface code (#6115) * BAEL2526 queue interface code * renamed test class to end with 'UnitTest', removed camel case from package name --- .../queueInterface/CustomBaeldungQueue.java | 48 +++++++++++++++++ .../queueInterface/PriorityQueueUnitTest.java | 53 +++++++++++++++++++ .../CustomBaeldungQueueUnitTest.java | 30 +++++++++++ 3 files changed, 131 insertions(+) create mode 100644 core-java-collections/src/main/java/com/baeldung/queueInterface/CustomBaeldungQueue.java create mode 100644 core-java-collections/src/test/java/com/baeldung/queueInterface/PriorityQueueUnitTest.java create mode 100644 core-java-collections/src/test/java/com/baeldung/queueinterface/CustomBaeldungQueueUnitTest.java diff --git a/core-java-collections/src/main/java/com/baeldung/queueInterface/CustomBaeldungQueue.java b/core-java-collections/src/main/java/com/baeldung/queueInterface/CustomBaeldungQueue.java new file mode 100644 index 0000000000..6b088a5079 --- /dev/null +++ b/core-java-collections/src/main/java/com/baeldung/queueInterface/CustomBaeldungQueue.java @@ -0,0 +1,48 @@ +package com.baeldung.queueinterface; + +import java.util.AbstractQueue; +import java.util.Iterator; +import java.util.LinkedList; + +public class CustomBaeldungQueue extends AbstractQueue { + + private LinkedList elements; + + public CustomBaeldungQueue() { + this.elements = new LinkedList(); + } + + @Override + public Iterator iterator() { + return elements.iterator(); + } + + @Override + public int size() { + return elements.size(); + } + + @Override + public boolean offer(T t) { + if(t == null) return false; + elements.add(t); + return true; + } + + @Override + public T poll() { + + Iterator iter = elements.iterator(); + T t = iter.next(); + if(t != null){ + iter.remove(); + return t; + } + return null; + } + + @Override + public T peek() { + return elements.getFirst(); + } +} diff --git a/core-java-collections/src/test/java/com/baeldung/queueInterface/PriorityQueueUnitTest.java b/core-java-collections/src/test/java/com/baeldung/queueInterface/PriorityQueueUnitTest.java new file mode 100644 index 0000000000..c5b564b55b --- /dev/null +++ b/core-java-collections/src/test/java/com/baeldung/queueInterface/PriorityQueueUnitTest.java @@ -0,0 +1,53 @@ +package com.baeldung.queueinterface; + +import org.junit.Before; +import org.junit.Test; + +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; + +public class PriorityQueueUnitTest { + + + + @Test + public void givenIntegerQueue_whenIntegersOutOfOrder_checkRetrievalOrderIsNatural() { + + PriorityQueue integerQueue = new PriorityQueue<>(); + + integerQueue.add(9); + integerQueue.add(2); + integerQueue.add(4); + + int first = integerQueue.poll(); + int second = integerQueue.poll(); + int third = integerQueue.poll(); + + assertEquals(2, first); + assertEquals(4, second); + assertEquals(9, third); + + + } + + @Test + public void givenStringQueue_whenStringsAddedOutOfNaturalOrder_checkRetrievalOrderNatural() { + + PriorityQueue stringQueue = new PriorityQueue<>(); + + stringQueue.add("banana"); + stringQueue.add("apple"); + stringQueue.add("cherry"); + + String first = stringQueue.poll(); + String second = stringQueue.poll(); + String third = stringQueue.poll(); + + assertEquals("apple", first); + assertEquals("banana", second); + assertEquals("cherry", third); + + + } +} diff --git a/core-java-collections/src/test/java/com/baeldung/queueinterface/CustomBaeldungQueueUnitTest.java b/core-java-collections/src/test/java/com/baeldung/queueinterface/CustomBaeldungQueueUnitTest.java new file mode 100644 index 0000000000..6dec768542 --- /dev/null +++ b/core-java-collections/src/test/java/com/baeldung/queueinterface/CustomBaeldungQueueUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.queueinterface; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CustomBaeldungQueueUnitTest { + + private CustomBaeldungQueue customQueue; + + @Before + public void setUp() throws Exception { + customQueue = new CustomBaeldungQueue<>(); + } + + @Test + public void givenQueueWithTwoElements_whenElementsRetrieved_checkRetrievalCorrect() { + + customQueue.add(7); + customQueue.add(5); + + int first = customQueue.poll(); + int second = customQueue.poll(); + + assertEquals(7, first); + assertEquals(5, second); + + } +} From 128817cfebe533b21c4248f6d14099579108a52d Mon Sep 17 00:00:00 2001 From: Amy DeGregorio Date: Wed, 9 Jan 2019 15:20:47 -0500 Subject: [PATCH 126/139] example code for Article How to Write to a CSV File in Java (#6102) --- .../com/baeldung/csv/WriteCsvFileExample.java | 29 ++++++ .../csv/WriteCsvFileExampleUnitTest.java | 90 +++++++++++++++++++ .../src/test/resources/exampleOutput.csv | 2 + 3 files changed, 121 insertions(+) create mode 100644 core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java create mode 100644 core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java create mode 100644 core-java-io/src/test/resources/exampleOutput.csv diff --git a/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java b/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java new file mode 100644 index 0000000000..fd3678d2c5 --- /dev/null +++ b/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java @@ -0,0 +1,29 @@ +package com.baeldung.csv; + +import java.io.BufferedWriter; +import java.io.IOException; + +public class WriteCsvFileExample { + + public void writeLine(BufferedWriter writer, String[] data) throws IOException { + StringBuilder csvLine = new StringBuilder(); + + for (int i = 0; i < data.length; i++) { + if (i > 0) { + csvLine.append(","); + } + csvLine.append(escapeSpecialCharacters(data[i])); + } + + writer.write(csvLine.toString()); + } + + public String escapeSpecialCharacters(String data) { + String escapedData = data.replaceAll("\\R", " "); + if (data.contains(",") || data.contains("\"") || data.contains("'")) { + data = data.replace("\"", "\"\""); + escapedData = "\"" + data + "\""; + } + return escapedData; + } +} diff --git a/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java new file mode 100644 index 0000000000..4ac84f939d --- /dev/null +++ b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java @@ -0,0 +1,90 @@ +package com.baeldung.csv; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WriteCsvFileExampleUnitTest { + private static final Logger LOG = LoggerFactory.getLogger(WriteCsvFileExampleUnitTest.class); + + private static final String CSV_FILE_NAME = "src/test/resources/exampleOutput.csv"; + private WriteCsvFileExample csvExample; + + @Before + public void setupClass() { + csvExample = new WriteCsvFileExample(); + } + + @Test + public void givenCommaContainingData_whenEscapeSpecialCharacters_stringReturnedInQuotes() { + String data = "three,two,one"; + String escapedData = csvExample.escapeSpecialCharacters(data); + + String expectedData = "\"three,two,one\""; + assertEquals(expectedData, escapedData); + } + + @Test + public void givenQuoteContainingData_whenEscapeSpecialCharacters_stringReturnedFormatted() { + String data = "She said \"Hello\""; + String escapedData = csvExample.escapeSpecialCharacters(data); + + String expectedData = "\"She said \"\"Hello\"\"\""; + assertEquals(expectedData, escapedData); + } + + @Test + public void givenNewlineContainingData_whenEscapeSpecialCharacters_stringReturnedInQuotes() { + String dataNewline = "This contains\na newline"; + String dataCarriageReturn = "This contains\r\na newline and carriage return"; + String escapedDataNl = csvExample.escapeSpecialCharacters(dataNewline); + String escapedDataCr = csvExample.escapeSpecialCharacters(dataCarriageReturn); + + String expectedData = "This contains a newline"; + assertEquals(expectedData, escapedDataNl); + String expectedDataCr = "This contains a newline and carriage return"; + assertEquals(expectedDataCr, escapedDataCr); + } + + @Test + public void givenNonSpecialData_whenEscapeSpecialCharacters_stringReturnedUnchanged() { + String data = "This is nothing special"; + String returnedData = csvExample.escapeSpecialCharacters(data); + + assertEquals(data, returnedData); + } + + @Test + public void givenBufferedWriter_whenWriteLine_thenOutputCreated() { + List dataLines = new ArrayList(); + dataLines.add(new String[] { "John", "Doe", "38", "Comment Data\nAnother line of comment data" }); + dataLines.add(new String[] { "Jane", "Doe, Jr.", "19", "She said \"I'm being quoted\"" }); + + File csvOutputFile = new File(CSV_FILE_NAME); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvOutputFile))) { + for (Iterator dataIterator = dataLines.iterator(); dataIterator.hasNext();) { + csvExample.writeLine(writer, dataIterator.next()); + if (dataIterator.hasNext()) { + writer.newLine(); + } + } + writer.flush(); + } catch (IOException e) { + LOG.error("IOException " + e.getMessage()); + } + + assertTrue(csvOutputFile.exists()); + } +} diff --git a/core-java-io/src/test/resources/exampleOutput.csv b/core-java-io/src/test/resources/exampleOutput.csv new file mode 100644 index 0000000000..45c37f3a3b --- /dev/null +++ b/core-java-io/src/test/resources/exampleOutput.csv @@ -0,0 +1,2 @@ +John,Doe,38,Comment Data Another line of comment data +Jane,"Doe, Jr.",19,"She said ""I'm being quoted""" \ No newline at end of file From 70a7aaa4fc25ad2d40e314d3f1c3ae8d8b760101 Mon Sep 17 00:00:00 2001 From: Kumar Chandrakant Date: Thu, 10 Jan 2019 02:20:46 +0530 Subject: [PATCH 127/139] Kafka spark cassandra (#6089) * Adding files for the tutorial BAEL-2301 * Incorporating review comments on the article. * Incorporated additional review comments on the article. --- .../data/pipeline/WordCountingApp.java | 18 ++++++------------ .../WordCountingAppWithCheckpoint.java | 19 ++++++------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java index 1155644e1e..db2a73b411 100644 --- a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingApp.java @@ -14,13 +14,7 @@ import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.spark.SparkConf; -import org.apache.spark.api.java.JavaPairRDD; import org.apache.spark.api.java.JavaRDD; -import org.apache.spark.api.java.function.FlatMapFunction; -import org.apache.spark.api.java.function.Function; -import org.apache.spark.api.java.function.Function2; -import org.apache.spark.api.java.function.PairFunction; -import org.apache.spark.api.java.function.VoidFunction; import org.apache.spark.streaming.Durations; import org.apache.spark.streaming.api.java.JavaDStream; import org.apache.spark.streaming.api.java.JavaInputDStream; @@ -59,17 +53,17 @@ public class WordCountingApp { JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); - JavaPairDStream results = messages.mapToPair((PairFunction, String, String>) record -> new Tuple2<>(record.key(), record.value())); + JavaPairDStream results = messages.mapToPair(record -> new Tuple2<>(record.key(), record.value())); - JavaDStream lines = results.map((Function, String>) tuple2 -> tuple2._2()); + JavaDStream lines = results.map(tuple2 -> tuple2._2()); - JavaDStream words = lines.flatMap((FlatMapFunction) x -> Arrays.asList(x.split("\\s+")) + JavaDStream words = lines.flatMap(x -> Arrays.asList(x.split("\\s+")) .iterator()); - JavaPairDStream wordCounts = words.mapToPair((PairFunction) s -> new Tuple2<>(s, 1)) - .reduceByKey((Function2) (i1, i2) -> i1 + i2); + JavaPairDStream wordCounts = words.mapToPair(s -> new Tuple2<>(s, 1)) + .reduceByKey((i1, i2) -> i1 + i2); - wordCounts.foreachRDD((VoidFunction>) javaRdd -> { + wordCounts.foreachRDD(javaRdd -> { Map wordCountMap = javaRdd.collectAsMap(); for (String key : wordCountMap.keySet()) { List wordList = Arrays.asList(new Word(key, wordCountMap.get(key))); diff --git a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java index 79e21f7209..efbe5f3851 100644 --- a/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java +++ b/apache-spark/src/main/java/com/baeldung/data/pipeline/WordCountingAppWithCheckpoint.java @@ -16,15 +16,8 @@ import org.apache.log4j.Logger; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; -import org.apache.spark.api.java.Optional; -import org.apache.spark.api.java.function.FlatMapFunction; -import org.apache.spark.api.java.function.Function; import org.apache.spark.api.java.function.Function2; -import org.apache.spark.api.java.function.Function3; -import org.apache.spark.api.java.function.PairFunction; -import org.apache.spark.api.java.function.VoidFunction; import org.apache.spark.streaming.Durations; -import org.apache.spark.streaming.State; import org.apache.spark.streaming.StateSpec; import org.apache.spark.streaming.api.java.JavaDStream; import org.apache.spark.streaming.api.java.JavaInputDStream; @@ -71,24 +64,24 @@ public class WordCountingAppWithCheckpoint { JavaInputDStream> messages = KafkaUtils.createDirectStream(streamingContext, LocationStrategies.PreferConsistent(), ConsumerStrategies. Subscribe(topics, kafkaParams)); - JavaPairDStream results = messages.mapToPair((PairFunction, String, String>) record -> new Tuple2<>(record.key(), record.value())); + JavaPairDStream results = messages.mapToPair(record -> new Tuple2<>(record.key(), record.value())); - JavaDStream lines = results.map((Function, String>) tuple2 -> tuple2._2()); + JavaDStream lines = results.map(tuple2 -> tuple2._2()); - JavaDStream words = lines.flatMap((FlatMapFunction) x -> Arrays.asList(x.split("\\s+")) + JavaDStream words = lines.flatMap(x -> Arrays.asList(x.split("\\s+")) .iterator()); - JavaPairDStream wordCounts = words.mapToPair((PairFunction) s -> new Tuple2<>(s, 1)) + JavaPairDStream wordCounts = words.mapToPair(s -> new Tuple2<>(s, 1)) .reduceByKey((Function2) (i1, i2) -> i1 + i2); - JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function((Function3, State, Tuple2>) (word, one, state) -> { + JavaMapWithStateDStream> cumulativeWordCounts = wordCounts.mapWithState(StateSpec.function((word, one, state) -> { int sum = one.orElse(0) + (state.exists() ? state.get() : 0); Tuple2 output = new Tuple2<>(word, sum); state.update(sum); return output; })); - cumulativeWordCounts.foreachRDD((VoidFunction>>) javaRdd -> { + cumulativeWordCounts.foreachRDD(javaRdd -> { List> wordCountList = javaRdd.collect(); for (Tuple2 tuple : wordCountList) { List wordList = Arrays.asList(new Word(tuple._1, tuple._2)); From 288fc3db8af02097cd1cb7bca13aa5a2569af9de Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 10 Jan 2019 01:04:16 +0200 Subject: [PATCH 128/139] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 324f6129db..07e90cca94 100644 --- a/pom.xml +++ b/pom.xml @@ -436,7 +436,7 @@ java-collections-conversions java-collections-maps - java-ee-8-security-api + java-lite java-numbers java-rmi From 57228dfc6b9ec1af0658f9b616056708c070bb28 Mon Sep 17 00:00:00 2001 From: Rodolfo Felipe Date: Wed, 9 Jan 2019 22:29:44 -0400 Subject: [PATCH 129/139] BAEL-2446 Unit tests for new added examples. --- .../StringReplaceAndRemoveUnitTest.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java b/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java index d952d2383b..d54bf09b35 100644 --- a/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java @@ -1,15 +1,16 @@ package com.baeldung.string; - import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.RegExUtils; import org.junit.Test; +import com.sun.source.tree.AssertTree; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class StringReplaceAndRemoveUnitTest { - @Test public void givenTestStrings_whenReplace_thenProcessedString() { @@ -26,7 +27,7 @@ public class StringReplaceAndRemoveUnitTest { public void givenTestStrings_whenReplaceAll_thenProcessedString() { String master2 = "Welcome to Baeldung, Hello World Baeldung"; - String regexTarget= "(Baeldung)$"; + String regexTarget = "(Baeldung)$"; String replacement = "Java"; String processed2 = master2.replaceAll(regexTarget, replacement); assertTrue(processed2.endsWith("Java")); @@ -45,18 +46,16 @@ public class StringReplaceAndRemoveUnitTest { StringBuilder builder = new StringBuilder(master); - builder.delete(startIndex, stopIndex); - assertFalse(builder.toString().contains(target)); - + assertFalse(builder.toString() + .contains(target)); builder.replace(startIndex, stopIndex, replacement); - assertTrue(builder.toString().contains(replacement)); - + assertTrue(builder.toString() + .contains(replacement)); } - @Test public void givenTestStrings_whenStringUtilsMethods_thenProcessedStrings() { @@ -74,10 +73,20 @@ public class StringReplaceAndRemoveUnitTest { } + @Test + public void givenTestStrings_whenReplaceExactWord_thenProcessedString() { + String sentence = "A car is not the same as a carriage, and some planes can carry cars inside them!"; + String regexTarget = "\\bcar\\b"; + String exactWordReplaced = sentence.replaceAll(regexTarget, "truck"); + assertTrue("A truck is not the same as a carriage, and some planes can carry cars inside them!".equals(exactWordReplaced)); + } - - - - + @Test + public void givenTestStrings_whenReplaceExactWordUsingRegExUtilsMethod_thenProcessedString() { + String sentence = "A car is not the same as a carriage, and some planes can carry cars inside them!"; + String regexTarget = "\\bcar\\b"; + String exactWordReplaced = RegExUtils.replaceAll(sentence, regexTarget, "truck"); + assertTrue("A truck is not the same as a carriage, and some planes can carry cars inside them!".equals(exactWordReplaced)); + } } From 44a796b9e66aa8ff28fa464ecaca486bdbcf0277 Mon Sep 17 00:00:00 2001 From: Rodolfo Felipe Date: Wed, 9 Jan 2019 23:16:44 -0400 Subject: [PATCH 130/139] Deleting invalid package Package added by eclipse. Nonexistent. --- .../com/baeldung/string/StringReplaceAndRemoveUnitTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java b/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java index d54bf09b35..4d2b54241b 100644 --- a/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java +++ b/java-strings/src/test/java/com/baeldung/string/StringReplaceAndRemoveUnitTest.java @@ -4,8 +4,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.RegExUtils; import org.junit.Test; -import com.sun.source.tree.AssertTree; - import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; From 4fb05ab3a27bc4267db4d344a3987e875d55537d Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 10 Jan 2019 21:22:46 +0200 Subject: [PATCH 131/139] Update pom.xml --- java-numbers/pom.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/java-numbers/pom.xml b/java-numbers/pom.xml index bb63c8cfe1..0f5140ea5e 100644 --- a/java-numbers/pom.xml +++ b/java-numbers/pom.xml @@ -72,16 +72,6 @@ - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IntegrationTest.java - - true - - org.apache.maven.plugins From dfbff7aa19384117e758e12ae1eab870d183f097 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 10 Jan 2019 21:32:08 +0200 Subject: [PATCH 132/139] Update pom.xml --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 07e90cca94..a9b4b3f119 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,7 @@ ${maven-war-plugin.version} + com.vackosar.gitflowincrementalbuilder From b8dbc9d053a6f56eb2884baa7c811b713ce7a2ae Mon Sep 17 00:00:00 2001 From: Laurentiu Delcea Date: Thu, 10 Jan 2019 23:21:06 +0200 Subject: [PATCH 133/139] BAEL-2480 Java Map to String conversion (#6075) * BAEL-2480 Java Map to String conversion * BAEL-2480 Java Map to String conversion * BAEL-2480 Java Map to String conversion * BAEL-2480 Java Map to String conversion --- .../com/baeldung/convert/MapToString.java | 34 +++++++++++++ .../com/baeldung/convert/StringToMap.java | 21 ++++++++ .../baeldung/convert/MapToStringUnitTest.java | 48 +++++++++++++++++++ .../baeldung/convert/StringToMapUnitTest.java | 23 +++++++++ 4 files changed, 126 insertions(+) create mode 100644 java-collections-maps/src/main/java/com/baeldung/convert/MapToString.java create mode 100644 java-collections-maps/src/main/java/com/baeldung/convert/StringToMap.java create mode 100644 java-collections-maps/src/test/java/com/baeldung/convert/MapToStringUnitTest.java create mode 100644 java-collections-maps/src/test/java/com/baeldung/convert/StringToMapUnitTest.java diff --git a/java-collections-maps/src/main/java/com/baeldung/convert/MapToString.java b/java-collections-maps/src/main/java/com/baeldung/convert/MapToString.java new file mode 100644 index 0000000000..aca0d05ef1 --- /dev/null +++ b/java-collections-maps/src/main/java/com/baeldung/convert/MapToString.java @@ -0,0 +1,34 @@ +package com.baeldung.convert; + +import com.google.common.base.Joiner; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; +import java.util.stream.Collectors; + +public class MapToString { + + public static String convertWithIteration(Map map) { + StringBuilder mapAsString = new StringBuilder("{"); + for (Integer key : map.keySet()) { + mapAsString.append(key + "=" + map.get(key) + ", "); + } + mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}"); + return mapAsString.toString(); + } + + public static String convertWithStream(Map map) { + String mapAsString = map.keySet().stream() + .map(key -> key + "=" + map.get(key)) + .collect(Collectors.joining(", ", "{", "}")); + return mapAsString; + } + + public static String convertWithGuava(Map map) { + return Joiner.on(",").withKeyValueSeparator("=").join(map); + } + + public static String convertWithApache(Map map) { + return StringUtils.join(map); + } +} diff --git a/java-collections-maps/src/main/java/com/baeldung/convert/StringToMap.java b/java-collections-maps/src/main/java/com/baeldung/convert/StringToMap.java new file mode 100644 index 0000000000..caabca4a09 --- /dev/null +++ b/java-collections-maps/src/main/java/com/baeldung/convert/StringToMap.java @@ -0,0 +1,21 @@ +package com.baeldung.convert; + +import com.google.common.base.Splitter; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public class StringToMap { + + public static Map convertWithStream(String mapAsString) { + Map map = Arrays.stream(mapAsString.split(",")) + .map(entry -> entry.split("=")) + .collect(Collectors.toMap(entry -> entry[0], entry -> entry[1])); + return map; + } + + public static Map convertWithGuava(String mapAsString) { + return Splitter.on(',').withKeyValueSeparator('=').split(mapAsString); + } +} diff --git a/java-collections-maps/src/test/java/com/baeldung/convert/MapToStringUnitTest.java b/java-collections-maps/src/test/java/com/baeldung/convert/MapToStringUnitTest.java new file mode 100644 index 0000000000..d9923e74a0 --- /dev/null +++ b/java-collections-maps/src/test/java/com/baeldung/convert/MapToStringUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.convert; + +import org.apache.commons.collections4.MapUtils; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class MapToStringUnitTest { + + private Map wordsByKey = new HashMap<>(); + + @BeforeEach + public void setup() { + wordsByKey.clear(); + wordsByKey.put(1, "one"); + wordsByKey.put(2, "two"); + wordsByKey.put(3, "three"); + wordsByKey.put(4, "four"); + } + + @Test + public void givenMap_WhenUsingIteration_ThenResultingMapIsCorrect() { + String mapAsString = MapToString.convertWithIteration(wordsByKey); + Assert.assertEquals("{1=one, 2=two, 3=three, 4=four}", mapAsString); + } + + @Test + public void givenMap_WhenUsingStream_ThenResultingMapIsCorrect() { + String mapAsString = MapToString.convertWithStream(wordsByKey); + Assert.assertEquals("{1=one, 2=two, 3=three, 4=four}", mapAsString); + } + + @Test + public void givenMap_WhenUsingGuava_ThenResultingMapIsCorrect() { + String mapAsString = MapToString.convertWithGuava(wordsByKey); + Assert.assertEquals("1=one,2=two,3=three,4=four", mapAsString); + } + + @Test + public void givenMap_WhenUsingApache_ThenResultingMapIsCorrect() { + String mapAsString = MapToString.convertWithApache(wordsByKey); + Assert.assertEquals("{1=one, 2=two, 3=three, 4=four}", mapAsString); + MapUtils.debugPrint(System.out, "Map as String", wordsByKey); + } +} \ No newline at end of file diff --git a/java-collections-maps/src/test/java/com/baeldung/convert/StringToMapUnitTest.java b/java-collections-maps/src/test/java/com/baeldung/convert/StringToMapUnitTest.java new file mode 100644 index 0000000000..8fb906efd0 --- /dev/null +++ b/java-collections-maps/src/test/java/com/baeldung/convert/StringToMapUnitTest.java @@ -0,0 +1,23 @@ +package com.baeldung.convert; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +public class StringToMapUnitTest { + + @Test + public void givenString_WhenUsingStream_ThenResultingStringIsCorrect() { + Map wordsByKey = StringToMap.convertWithStream("1=one,2=two,3=three,4=four"); + Assert.assertEquals(4, wordsByKey.size()); + Assert.assertEquals("one", wordsByKey.get("1")); + } + + @Test + void givenString_WhenUsingGuava_ThenResultingStringIsCorrect() { + Map wordsByKey = StringToMap.convertWithGuava("1=one,2=two,3=three,4=four"); + Assert.assertEquals(4, wordsByKey.size()); + Assert.assertEquals("one", wordsByKey.get("1")); + } +} \ No newline at end of file From c65180c74f75f2cbb0d21b787d12b9098865a703 Mon Sep 17 00:00:00 2001 From: Emily Cheyne Date: Thu, 10 Jan 2019 15:05:00 -0700 Subject: [PATCH 134/139] BAEL-2535 Remove CustomerReflectionToStringUnitTest --- .../CustomerReflectionToStringUnitTest.java | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java diff --git a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java b/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java deleted file mode 100644 index 77dcab52e6..0000000000 --- a/java-strings/src/test/java/com/baeldung/string/tostring/CustomerReflectionToStringUnitTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.string.tostring; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; - -public class CustomerReflectionToStringUnitTest { - private static final String CUSTOMER_REFLECTION_TO_STRING = "com.baeldung.string.tostring.CustomerReflectionToString"; - - @Test - public void givenWrapperCollectionStrBuffer_whenReflectionToString_thenCustomerDetails() { - CustomerReflectionToString customer = new CustomerReflectionToString(); - customer.setFirstName("Rajesh"); - customer.setLastName("Bhojwani"); - customer.setScore(8); - - List orders = new ArrayList(); - orders.add("Book"); - orders.add("Pen"); - customer.setOrders(orders); - - StringBuffer fullname = new StringBuffer(); - fullname.append(customer.getLastName()+", "+ customer.getFirstName()); - customer.setFullname(fullname); - - assertTrue(customer.toString().contains(CUSTOMER_REFLECTION_TO_STRING)); - } - -} From c5415eecac1322a79f30e6ecf9bcd946d231233d Mon Sep 17 00:00:00 2001 From: "Erick Audet M.Sc" Date: Thu, 10 Jan 2019 17:16:53 -0500 Subject: [PATCH 135/139] BAEL-2059 * New section in InputStream to byte array article and recreating branch. * Minor typo * Code reformat using intellij formatter. * Code reformat using intellij formatter. * guava implementation to be completed * guava implementation * Added assert to guava test * Fix formatting --- .../io/InputStreamToByteBufferUnitTest.java | 60 ++++++++++++++++++ .../resources/frontenac-2257154_960_720.jpg | Bin 0 -> 194684 bytes parent-java/pom.xml | 4 +- 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 core-java-io/src/test/java/org/baeldung/java/io/InputStreamToByteBufferUnitTest.java create mode 100644 core-java-io/src/test/resources/frontenac-2257154_960_720.jpg diff --git a/core-java-io/src/test/java/org/baeldung/java/io/InputStreamToByteBufferUnitTest.java b/core-java-io/src/test/java/org/baeldung/java/io/InputStreamToByteBufferUnitTest.java new file mode 100644 index 0000000000..fedadde04b --- /dev/null +++ b/core-java-io/src/test/java/org/baeldung/java/io/InputStreamToByteBufferUnitTest.java @@ -0,0 +1,60 @@ +package org.baeldung.java.io; + + +import com.google.common.io.ByteStreams; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class InputStreamToByteBufferUnitTest { + + @Test + public void givenUsingCoreClasses_whenWritingAFileIntoAByteBuffer_thenBytesLengthMustMatch() throws IOException { + File inputFile = getFile(); + ByteBuffer bufferByte = ByteBuffer.allocate((int) inputFile.length()); + FileInputStream in = new FileInputStream(inputFile); + in.getChannel().read(bufferByte); + + assertEquals(bufferByte.position(), inputFile.length()); + } + + @Test + public void givenUsingCommonsIo_whenWritingAFileIntoAByteBuffer_thenBytesLengthMustMatch() throws IOException { + File inputFile = getFile(); + ByteBuffer bufferByte = ByteBuffer.allocateDirect((int) inputFile.length()); + ReadableByteChannel readableByteChannel = new FileInputStream(inputFile).getChannel(); + IOUtils.readFully(readableByteChannel, bufferByte); + + assertEquals(bufferByte.position(), inputFile.length()); + } + + @Test + public void givenUsingGuava_whenWritingAFileIntoAByteBuffer_thenBytesLengthMustMatch() throws IOException { + File inputFile = getFile(); + FileInputStream in = new FileInputStream(inputFile); + byte[] targetArray = ByteStreams.toByteArray(in); + ByteBuffer bufferByte = ByteBuffer.wrap(targetArray); + bufferByte.rewind(); + while (bufferByte.hasRemaining()) { + bufferByte.get(); + } + + assertEquals(bufferByte.position(), inputFile.length()); + } + + private File getFile() { + ClassLoader classLoader = new InputStreamToByteBufferUnitTest().getClass().getClassLoader(); + + String fileName = "frontenac-2257154_960_720.jpg"; + + return new File(classLoader.getResource(fileName).getFile()); + } + +} diff --git a/core-java-io/src/test/resources/frontenac-2257154_960_720.jpg b/core-java-io/src/test/resources/frontenac-2257154_960_720.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77c459b0e39604cbac6d0bd59e6ef3fceb22061b GIT binary patch literal 194684 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 - 22.0 + 23.0 - \ No newline at end of file + From c4edb95d4ef6733a1e520249861950743c0fa54c Mon Sep 17 00:00:00 2001 From: Olaniyi Anjola Date: Thu, 10 Jan 2019 18:51:30 -0500 Subject: [PATCH 136/139] BAEL-2452: Using curl from Java (#6113) * Renamed from Unit Test to Live Test * Update JavaCurlExamplesLiveTest.java --- ...est.java => JavaCurlExamplesLiveTest.java} | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) rename core-java/src/test/java/com/baeldung/curltojava/{JavaCurlExamplesUnitTest.java => JavaCurlExamplesLiveTest.java} (56%) diff --git a/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesLiveTest.java similarity index 56% rename from core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java rename to core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesLiveTest.java index 4e82059f2b..2ec62cbbf9 100644 --- a/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesUnitTest.java +++ b/core-java/src/test/java/com/baeldung/curltojava/JavaCurlExamplesLiveTest.java @@ -3,19 +3,16 @@ package com.baeldung.curltojava; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; import org.junit.Assert; import org.junit.Test; -public class JavaCurlExamplesUnitTest { - +public class JavaCurlExamplesLiveTest { @Test public void givenCommand_whenCalled_thenProduceZeroExitCode() throws IOException { - String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; - ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + String command = "curl -X GET https://postman-echo.com/get?foo1=bar1&foo2=bar2"; + ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")); processBuilder.directory(new File("/home/")); Process process = processBuilder.start(); InputStream inputStream = process.getInputStream(); @@ -28,8 +25,8 @@ public class JavaCurlExamplesUnitTest { @Test public void givenNewCommands_whenCalled_thenCheckIfIsAlive() throws IOException { - String command = "curl --location --request GET \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\""; - ProcessBuilder processBuilder = new ProcessBuilder(command.replaceAll("\"", "").split(" ")); + String command = "curl -X GET https://postman-echo.com/get?foo1=bar1&foo2=bar2"; + ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")); processBuilder.directory(new File("/home/")); Process process = processBuilder.start(); @@ -40,16 +37,14 @@ public class JavaCurlExamplesUnitTest { } @Test - public void whenRequestGet_thenReturnSuccessResponseCode() throws IOException { - String url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2"; - URL urlObj = new URL(url); - HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); - connection.setDoOutput(true); - connection.setInstanceFollowRedirects(false); - connection.setRequestMethod("GET"); - connection.connect(); + public void whenRequestPost_thenCheckIfReturnContent() throws IOException { + String command = "curl -X POST https://postman-echo.com/post --data foo1=bar1&foo2=bar2"; + Process process = Runtime.getRuntime().exec(command); - Assert.assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode()); + // Get the POST result + String content = JavaCurlExamples.inputStreamToString(process.getInputStream()); + + Assert.assertTrue(null != content && !content.isEmpty()); } } From 36e48924468b9030ec382bf537084635785fc5e1 Mon Sep 17 00:00:00 2001 From: Upendra Chintala Date: Fri, 11 Jan 2019 18:13:27 +0530 Subject: [PATCH 137/139] Check if a year/date is a leap year in Java (#6086) * Hexagonal architecture implementation in Java - upendra.chintala@gmail.com * An example program to find a leap year using java 8 java.time.Year API * Changed to add assertions * Remvoed evaluation article code * Added unit test suite for leap year testing using java.time.Year and java.util.GregorianCalendar * Update LeapYearUnitTest.java * Update LeapYearUnitTest.java --- .../baeldung/leapyear/LeapYearUnitTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java b/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java new file mode 100644 index 0000000000..9fb3d03838 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.leapyear; + +import java.time.Year; +import java.util.GregorianCalendar; + +import org.junit.Assert; +import org.junit.Test; + +public class LeapYearUnitTest { + + //Before Java8 + @Test + public void testLeapYearUsingGregorianCalendar () { + Assert.assertFalse(new GregorianCalendar().isLeapYear(2018)); + } + + //Java 8 and above + @Test + public void testLeapYearUsingJavaTimeYear () { + Assert.assertTrue(Year.isLeap(2012)); + } + + @Test + public void testBCYearUsingJavaTimeYear () { + Assert.assertTrue(Year.isLeap(-4)); + } + + @Test + public void testWrongLeapYearUsingJavaTimeYear () { + Assert.assertFalse(Year.isLeap(2018)); + } + + @Test + public void testLeapYearInDateUsingJavaTimeYear () { + LocalDate date = LocalDate.parse("2020-01-05", DateTimeFormatter.ISO_LOCAL_DATE); + Assert.assertTrue(Year.from(date).isLeap()); + } + +} From 583969b59d09e3a975e3da06823270a217103e41 Mon Sep 17 00:00:00 2001 From: Amy DeGregorio Date: Fri, 11 Jan 2019 13:28:10 -0500 Subject: [PATCH 138/139] BAEL-2499 Write to CSV in Java - Updated PR (#6122) * example code for Article How to Write to a CSV File in Java * Updated to use a Stream --- .../com/baeldung/csv/WriteCsvFileExample.java | 7 ++----- .../csv/WriteCsvFileExampleUnitTest.java | 20 +++++++------------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java b/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java index fd3678d2c5..e1237481b1 100644 --- a/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java +++ b/core-java-io/src/main/java/com/baeldung/csv/WriteCsvFileExample.java @@ -1,11 +1,8 @@ package com.baeldung.csv; -import java.io.BufferedWriter; -import java.io.IOException; - public class WriteCsvFileExample { - public void writeLine(BufferedWriter writer, String[] data) throws IOException { + public String convertToCSV(String[] data) { StringBuilder csvLine = new StringBuilder(); for (int i = 0; i < data.length; i++) { @@ -15,7 +12,7 @@ public class WriteCsvFileExample { csvLine.append(escapeSpecialCharacters(data[i])); } - writer.write(csvLine.toString()); + return csvLine.toString(); } public String escapeSpecialCharacters(String data) { diff --git a/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java index 4ac84f939d..e30ec0818c 100644 --- a/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java +++ b/core-java-io/src/test/java/com/baeldung/csv/WriteCsvFileExampleUnitTest.java @@ -3,12 +3,10 @@ package com.baeldung.csv; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.junit.Before; @@ -73,15 +71,11 @@ public class WriteCsvFileExampleUnitTest { dataLines.add(new String[] { "Jane", "Doe, Jr.", "19", "She said \"I'm being quoted\"" }); File csvOutputFile = new File(CSV_FILE_NAME); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvOutputFile))) { - for (Iterator dataIterator = dataLines.iterator(); dataIterator.hasNext();) { - csvExample.writeLine(writer, dataIterator.next()); - if (dataIterator.hasNext()) { - writer.newLine(); - } - } - writer.flush(); - } catch (IOException e) { + try (PrintWriter pw = new PrintWriter(csvOutputFile)) { + dataLines.stream() + .map(csvExample::convertToCSV) + .forEach(pw::println); + } catch (FileNotFoundException e) { LOG.error("IOException " + e.getMessage()); } From 4b47306e913180c1c4da86f6f507a3d1724b28f5 Mon Sep 17 00:00:00 2001 From: Emily Cheyne Date: Fri, 11 Jan 2019 12:48:28 -0700 Subject: [PATCH 139/139] BAEL-2535 --- java-strings/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/java-strings/README.md b/java-strings/README.md index 08fbec35ab..b72a378d06 100644 --- a/java-strings/README.md +++ b/java-strings/README.md @@ -49,3 +49,4 @@ - [Add a Character to a String at a Given Position](https://www.baeldung.com/java-add-character-to-string) - [Remove Leading and Trailing Characters from a String](https://www.baeldung.com/java-remove-trailing-characters) - [Concatenating Strings In Java](https://www.baeldung.com/java-strings-concatenation) +- [Java toString() Method](https://www.baeldung.com/java-tostring)