From a4d768763b9275d717c92bdf19ea93f4186dfd15 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 6 Dec 2018 15:23:13 +0400 Subject: [PATCH 01/70] 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 02/70] 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 64b205a6ce2360de18c418fef3da2e53f1468e90 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Fri, 21 Dec 2018 12:19:09 +0400 Subject: [PATCH 03/70] 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 5dd6d520254050e3378cbc06c46f1985467a8557 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 27 Dec 2018 12:48:51 +0400 Subject: [PATCH 04/70] 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 c39fe1c85ca175a028521f8bf77ef9a906e24a6f Mon Sep 17 00:00:00 2001 From: Markus Gulden <> Date: Tue, 1 Jan 2019 15:40:15 +0100 Subject: [PATCH 05/70] 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 66016332f82446179aaae1ed5bd41c15b26773c0 Mon Sep 17 00:00:00 2001 From: Mikhail Chugunov Date: Wed, 2 Jan 2019 19:09:00 +0300 Subject: [PATCH 06/70] BAEL-2475: Add sample code and tests --- .../immutable/MaritalAwarePerson.java | 58 +++++++++++++++++++ .../deserialization/immutable/Person.java | 24 ++++++++ ...mmutableObjectDeserializationUnitTest.java | 40 +++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java create mode 100644 jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java create mode 100644 jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java new file mode 100644 index 0000000000..cb593b3bb7 --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java @@ -0,0 +1,58 @@ +package com.baeldung.jackson.deserialization.immutable; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonDeserialize(builder = MaritalAwarePerson.Builder.class) +public class MaritalAwarePerson { + + private final String name; + private final int age; + private final Boolean married; + + private MaritalAwarePerson(String name, int age, Boolean married) { + this.name = name; + this.age = age; + this.married = married; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public Boolean getMarried() { + return married; + } + + @JsonPOJOBuilder + static class Builder { + String name; + int age; + Boolean married; + + Builder withName(String name) { + this.name = name; + return this; + } + + Builder withAge(int age) { + this.age = age; + return this; + } + + Builder withMarried(boolean married) { + this.married = married; + return this; + } + + public MaritalAwarePerson build() { + return new MaritalAwarePerson(name, age, married); + } + + + } +} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java new file mode 100644 index 0000000000..0214f93ca9 --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java @@ -0,0 +1,24 @@ +package com.baeldung.jackson.deserialization.immutable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Person { + + private final String name; + private final int age; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Person(@JsonProperty("name") String name, @JsonProperty("age") int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java new file mode 100644 index 0000000000..348ece4a09 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.jackson.deserialization.immutable; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class ImmutableObjectDeserializationUnitTest { + + @Test + public void testPublicConstructor() throws IOException { + final String json = "{\"name\":\"Frank\",\"age\":50}"; + Person person = new ObjectMapper().readValue(json, Person.class); + + assertEquals("Frank", person.getName()); + assertEquals(50, person.getAge()); + } + + @Test + public void testBuilderNullField() throws IOException { + final String json = "{\"name\":\"Frank\",\"age\":50}"; + MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); + + assertEquals("Frank", person.getName()); + assertEquals(50, person.getAge()); + assertNull(person.getMarried()); + } + + @Test + public void testBuilderAllFields() throws IOException { + final String json = "{\"name\":\"Frank\",\"age\":50,\"married\":true}"; + MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); + + assertEquals("Frank", person.getName()); + assertEquals(50, person.getAge()); + assertTrue(person.getMarried()); + } +} From 2e436ce3e8e31c6791257f624b9661b4ba3368b3 Mon Sep 17 00:00:00 2001 From: Mikhail Chugunov Date: Wed, 2 Jan 2019 19:14:09 +0300 Subject: [PATCH 07/70] BAEL-2475: Rename tests --- .../immutable/ImmutableObjectDeserializationUnitTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java index 348ece4a09..5c33a2da26 100644 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java @@ -10,7 +10,7 @@ import static org.junit.Assert.*; public class ImmutableObjectDeserializationUnitTest { @Test - public void testPublicConstructor() throws IOException { + public void whenPublicConstructorIsUsed_thenObjectIsDeserialized() throws IOException { final String json = "{\"name\":\"Frank\",\"age\":50}"; Person person = new ObjectMapper().readValue(json, Person.class); @@ -19,7 +19,7 @@ public class ImmutableObjectDeserializationUnitTest { } @Test - public void testBuilderNullField() throws IOException { + public void whenBuilderIsUsedAndFieldIsNull_thenObjectIsDeserialized() throws IOException { final String json = "{\"name\":\"Frank\",\"age\":50}"; MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); @@ -29,7 +29,7 @@ public class ImmutableObjectDeserializationUnitTest { } @Test - public void testBuilderAllFields() throws IOException { + public void whenBuilderIsUsedAndAllFieldsPresent_thenObjectIsDeserialized() throws IOException { final String json = "{\"name\":\"Frank\",\"age\":50,\"married\":true}"; MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); From 75bf7ba5155da5fd1b8240080e35c4f0adb8781f Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Wed, 2 Jan 2019 22:11:21 +0530 Subject: [PATCH 08/70] 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 09/70] 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 eacc84a450dad6e85354ea7e3acf72e902dcae19 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Thu, 3 Jan 2019 08:08:25 +0530 Subject: [PATCH 10/70] 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 4eb3f2943038f3b0635e8267b7e9a666af6281d9 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Thu, 3 Jan 2019 22:42:26 +0530 Subject: [PATCH 11/70] 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 12/70] 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 082724abecd4bc514baadc96b4a3046570254609 Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Sat, 5 Jan 2019 10:38:13 +0530 Subject: [PATCH 13/70] 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 20e8886165192cd55e5151120b07ff0029242e28 Mon Sep 17 00:00:00 2001 From: Kumar Chandrakant Date: Sun, 6 Jan 2019 19:26:21 +0530 Subject: [PATCH 14/70] 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 15/70] 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 16/70] [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 17/70] 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 18/70] 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 19/70] 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 20/70] 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 115a52a124ce455bbe1c844a6cea93ed3d56cae8 Mon Sep 17 00:00:00 2001 From: Urvy Agrawal Date: Mon, 7 Jan 2019 22:03:52 +0530 Subject: [PATCH 21/70] Adding files for BAEL-2543 --- .../java/com/baeldung/keyword/Circle.java | 4 ++ .../main/java/com/baeldung/keyword/Ring.java | 4 ++ .../main/java/com/baeldung/keyword/Round.java | 4 ++ .../main/java/com/baeldung/keyword/Shape.java | 4 ++ .../java/com/baeldung/keyword/Triangle.java | 4 ++ .../keyword/test/InstanceOfUnitTest.java | 49 +++++++++++++++++++ 6 files changed, 69 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/keyword/Circle.java create mode 100644 core-java/src/main/java/com/baeldung/keyword/Ring.java create mode 100644 core-java/src/main/java/com/baeldung/keyword/Round.java create mode 100644 core-java/src/main/java/com/baeldung/keyword/Shape.java create mode 100644 core-java/src/main/java/com/baeldung/keyword/Triangle.java create mode 100644 core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java diff --git a/core-java/src/main/java/com/baeldung/keyword/Circle.java b/core-java/src/main/java/com/baeldung/keyword/Circle.java new file mode 100644 index 0000000000..4ec91d1b8a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/keyword/Circle.java @@ -0,0 +1,4 @@ +package com.baeldung.keyword; + +public class Circle extends Round implements Shape { +} diff --git a/core-java/src/main/java/com/baeldung/keyword/Ring.java b/core-java/src/main/java/com/baeldung/keyword/Ring.java new file mode 100644 index 0000000000..99873f9640 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/keyword/Ring.java @@ -0,0 +1,4 @@ +package com.baeldung.keyword; + +public class Ring extends Round { +} diff --git a/core-java/src/main/java/com/baeldung/keyword/Round.java b/core-java/src/main/java/com/baeldung/keyword/Round.java new file mode 100644 index 0000000000..0e2cc2c8c7 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/keyword/Round.java @@ -0,0 +1,4 @@ +package com.baeldung.keyword; + +public class Round { +} diff --git a/core-java/src/main/java/com/baeldung/keyword/Shape.java b/core-java/src/main/java/com/baeldung/keyword/Shape.java new file mode 100644 index 0000000000..8d00c165a3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/keyword/Shape.java @@ -0,0 +1,4 @@ +package com.baeldung.keyword; + +public interface Shape { +} diff --git a/core-java/src/main/java/com/baeldung/keyword/Triangle.java b/core-java/src/main/java/com/baeldung/keyword/Triangle.java new file mode 100644 index 0000000000..406b8f23e5 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/keyword/Triangle.java @@ -0,0 +1,4 @@ +package com.baeldung.keyword; + +public class Triangle implements Shape { +} diff --git a/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java b/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java new file mode 100644 index 0000000000..fbeec3a077 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.keyword.test; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import com.baeldung.keyword.Circle; +import com.baeldung.keyword.Ring; +import com.baeldung.keyword.Round; +import com.baeldung.keyword.Shape; +import com.baeldung.keyword.Triangle; + +public class InstanceOfUnitTest { + + @Test + public void giveWhenInstanceIsCorrect_thenReturnTrue() { + Ring ring = new Ring(); + Assert.assertTrue("ring is instance of Round ", ring instanceof Round); + } + + @Test + public void giveWhenObjectIsInstanceOfType_thenReturnTrue() { + Circle circle = new Circle(); + Assert.assertTrue("circle is instance of Circle ", circle instanceof Circle); + } + + + @Test + public void giveWhenInstanceIsOfSubtype_thenReturnTrue() { + Circle circle = new Circle(); + Assert.assertTrue("circle is instance of Round", circle instanceof Round); + } + + @Test + public void giveWhenTypeIsInterface_thenReturnTrue() { + Circle circle = new Circle(); + Assert.assertTrue("circle is instance of Shape", circle instanceof Shape); + } + + @Test + public void giveWhenInstanceValueIsNull_thenReturnFalse() { + Circle circle = null; + Assert.assertFalse("circle is instance of Round", circle instanceof Round); + } + + @Test + public void giveWhenComparingClassInDiffHierarchy_thenCompilationError() { + // Assert.assertFalse("circle is instance of Triangle", circle instanceof Triangle); + } +} From 43b0770e134802ad328b6282c86af8ac2a729954 Mon Sep 17 00:00:00 2001 From: Emily Cheyne Date: Mon, 7 Jan 2019 18:36:15 -0700 Subject: [PATCH 22/70] 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 23/70] 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 24/70] 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 25/70] 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 26/70] 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 27/70] 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 26101769311c7de0285f23e34f00c90187e53f64 Mon Sep 17 00:00:00 2001 From: Urvy Agrawal Date: Tue, 8 Jan 2019 20:09:51 +0530 Subject: [PATCH 28/70] Review comments added --- .../java/com/baeldung/keyword/test/InstanceOfUnitTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java b/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java index fbeec3a077..4c010e3a16 100644 --- a/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java +++ b/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java @@ -35,6 +35,12 @@ public class InstanceOfUnitTest { Circle circle = new Circle(); Assert.assertTrue("circle is instance of Shape", circle instanceof Shape); } + + @Test + public void giveWhenTypeIsOfObjectType_thenReturnTrue() { + Thread thread = new Thread(); + Assert.assertTrue("thread is instance of Object", thread instanceof Object); + } @Test public void giveWhenInstanceValueIsNull_thenReturnFalse() { From f1fa9c8253a9db826ad4de40dd71be2ec2ac7527 Mon Sep 17 00:00:00 2001 From: pandachris Date: Tue, 8 Jan 2019 22:18:47 +0700 Subject: [PATCH 29/70] 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 30/70] 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 31/70] 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 32/70] 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 33/70] 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 34/70] 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 a094e49a6292aaad494f6d66194066c69a81c43f Mon Sep 17 00:00:00 2001 From: Mikhail Chugunov Date: Wed, 9 Jan 2019 19:53:12 +0300 Subject: [PATCH 35/70] BAEL-2475: Changes after first review --- .../deserialization/immutable/Employee.java | 24 ++++++++ .../immutable/MaritalAwarePerson.java | 58 ------------------- .../deserialization/immutable/Person.java | 32 ++++++++-- ...mmutableObjectDeserializationUnitTest.java | 22 ++++--- 4 files changed, 60 insertions(+), 76 deletions(-) create mode 100644 jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Employee.java delete mode 100644 jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Employee.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Employee.java new file mode 100644 index 0000000000..44b10ee39b --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Employee.java @@ -0,0 +1,24 @@ +package com.baeldung.jackson.deserialization.immutable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Employee { + + private final long id; + private final String name; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public Employee(@JsonProperty("id") long id, @JsonProperty("name") String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java deleted file mode 100644 index cb593b3bb7..0000000000 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/MaritalAwarePerson.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.baeldung.jackson.deserialization.immutable; - -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; - -@JsonDeserialize(builder = MaritalAwarePerson.Builder.class) -public class MaritalAwarePerson { - - private final String name; - private final int age; - private final Boolean married; - - private MaritalAwarePerson(String name, int age, Boolean married) { - this.name = name; - this.age = age; - this.married = married; - } - - public String getName() { - return name; - } - - public int getAge() { - return age; - } - - public Boolean getMarried() { - return married; - } - - @JsonPOJOBuilder - static class Builder { - String name; - int age; - Boolean married; - - Builder withName(String name) { - this.name = name; - return this; - } - - Builder withAge(int age) { - this.age = age; - return this; - } - - Builder withMarried(boolean married) { - this.married = married; - return this; - } - - public MaritalAwarePerson build() { - return new MaritalAwarePerson(name, age, married); - } - - - } -} diff --git a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java index 0214f93ca9..d9041720b6 100644 --- a/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java +++ b/jackson/src/main/java/com/baeldung/jackson/deserialization/immutable/Person.java @@ -1,15 +1,15 @@ package com.baeldung.jackson.deserialization.immutable; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +@JsonDeserialize(builder = Person.Builder.class) public class Person { private final String name; - private final int age; + private final Integer age; - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Person(@JsonProperty("name") String name, @JsonProperty("age") int age) { + private Person(String name, Integer age) { this.name = name; this.age = age; } @@ -18,7 +18,27 @@ public class Person { return name; } - public int getAge() { + public Integer getAge() { return age; } + + @JsonPOJOBuilder + static class Builder { + String name; + Integer age; + + Builder withName(String name) { + this.name = name; + return this; + } + + Builder withAge(Integer age) { + this.age = age; + return this; + } + + Person build() { + return new Person(name, age); + } + } } diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java index 5c33a2da26..1252179e3a 100644 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/deserialization/immutable/ImmutableObjectDeserializationUnitTest.java @@ -11,30 +11,28 @@ public class ImmutableObjectDeserializationUnitTest { @Test public void whenPublicConstructorIsUsed_thenObjectIsDeserialized() throws IOException { - final String json = "{\"name\":\"Frank\",\"age\":50}"; - Person person = new ObjectMapper().readValue(json, Person.class); + final String json = "{\"name\":\"Frank\",\"id\":5000}"; + Employee employee = new ObjectMapper().readValue(json, Employee.class); - assertEquals("Frank", person.getName()); - assertEquals(50, person.getAge()); + assertEquals("Frank", employee.getName()); + assertEquals(5000, employee.getId()); } @Test public void whenBuilderIsUsedAndFieldIsNull_thenObjectIsDeserialized() throws IOException { - final String json = "{\"name\":\"Frank\",\"age\":50}"; - MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); + final String json = "{\"name\":\"Frank\"}"; + Person person = new ObjectMapper().readValue(json, Person.class); assertEquals("Frank", person.getName()); - assertEquals(50, person.getAge()); - assertNull(person.getMarried()); + assertNull(person.getAge()); } @Test public void whenBuilderIsUsedAndAllFieldsPresent_thenObjectIsDeserialized() throws IOException { - final String json = "{\"name\":\"Frank\",\"age\":50,\"married\":true}"; - MaritalAwarePerson person = new ObjectMapper().readValue(json, MaritalAwarePerson.class); + final String json = "{\"name\":\"Frank\",\"age\":50}"; + Person person = new ObjectMapper().readValue(json, Person.class); assertEquals("Frank", person.getName()); - assertEquals(50, person.getAge()); - assertTrue(person.getMarried()); + assertEquals(50, (int) person.getAge()); } } From 44490a052ff0760b5115ba5764e53553c41ccf44 Mon Sep 17 00:00:00 2001 From: Sam Millington Date: Wed, 9 Jan 2019 18:06:47 +0000 Subject: [PATCH 36/70] 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 37/70] 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 38/70] 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 39/70] 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 c7ba38ffcd805b088e9e44d7145eb393ef162025 Mon Sep 17 00:00:00 2001 From: geroza Date: Tue, 8 Jan 2019 16:16:51 -0200 Subject: [PATCH 40/70] migrated the following modules using parent-spring-5 to spring 5.1: spring-mvc-simple spring-security-mvc-custom spring-security-mvc-login spring-security-rest spring-security-rest-basic-auth spring-static-resources spring-thymeleaf --- ethereum/pom.xml | 4 +- parent-spring-5-1/README.md | 1 + parent-spring-5-1/pom.xml | 39 +++++++++++++++++++ parent-spring-5/pom.xml | 4 +- .../spring-data-elasticsearch/pom.xml | 4 +- .../spring-data-mongodb/pom.xml | 5 +-- pom.xml | 6 +++ spring-dispatcher-servlet/pom.xml | 4 +- spring-mvc-forms-jsp/pom.xml | 4 +- spring-mvc-java/pom.xml | 4 +- spring-mvc-simple/pom.xml | 19 --------- .../java/com/baeldung/spring/MvcConfig.java | 1 - .../baeldung/client/RestTemplateFactory.java | 4 +- .../java/org/baeldung/spring/WebConfig.java | 1 - .../SpringContextIntegrationTest.java | 2 +- .../java/org/baeldung/web/FooLiveTest.java | 2 +- 16 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 parent-spring-5-1/README.md create mode 100644 parent-spring-5-1/pom.xml diff --git a/ethereum/pom.xml b/ethereum/pom.xml index 85cb260670..334840edaf 100644 --- a/ethereum/pom.xml +++ b/ethereum/pom.xml @@ -7,10 +7,10 @@ ethereum - parent-spring-5 + parent-spring-5-1 com.baeldung 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-5-1 diff --git a/parent-spring-5-1/README.md b/parent-spring-5-1/README.md new file mode 100644 index 0000000000..ff12555376 --- /dev/null +++ b/parent-spring-5-1/README.md @@ -0,0 +1 @@ +## Relevant articles: diff --git a/parent-spring-5-1/pom.xml b/parent-spring-5-1/pom.xml new file mode 100644 index 0000000000..983e5e63eb --- /dev/null +++ b/parent-spring-5-1/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + com.baeldung + parent-spring-5-1 + 0.0.1-SNAPSHOT + pom + parent-spring-5-1 + Parent for all spring 5 core modules + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.springframework + spring-core + ${spring.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + + 5.0.6.RELEASE + 5.0.2 + 2.9.6 + 2.9.6 + 5.0.6.RELEASE + + + diff --git a/parent-spring-5/pom.xml b/parent-spring-5/pom.xml index 6a15f38884..51a2c1fd1f 100644 --- a/parent-spring-5/pom.xml +++ b/parent-spring-5/pom.xml @@ -29,11 +29,11 @@ - 5.0.6.RELEASE + 5.1.2.RELEASE 5.0.2 2.9.6 2.9.6 - 5.0.6.RELEASE + 5.1.2.RELEASE \ No newline at end of file diff --git a/persistence-modules/spring-data-elasticsearch/pom.xml b/persistence-modules/spring-data-elasticsearch/pom.xml index ee9e71a1cb..c5ad9b64f9 100644 --- a/persistence-modules/spring-data-elasticsearch/pom.xml +++ b/persistence-modules/spring-data-elasticsearch/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-spring-5 + parent-spring-5-1 0.0.1-SNAPSHOT - ../../parent-spring-5 + ../../parent-spring-5-1 diff --git a/persistence-modules/spring-data-mongodb/pom.xml b/persistence-modules/spring-data-mongodb/pom.xml index 63b9c3c1b0..4da0526ca6 100644 --- a/persistence-modules/spring-data-mongodb/pom.xml +++ b/persistence-modules/spring-data-mongodb/pom.xml @@ -6,9 +6,9 @@ com.baeldung - parent-spring-5 + parent-spring-5-1 0.0.1-SNAPSHOT - ../../parent-spring-5 + ../../parent-spring-5-1 @@ -99,7 +99,6 @@ 2.1.2.RELEASE 4.1.4 1.1.3 - 5.1.0.RELEASE 1.9.2 3.2.0.RELEASE diff --git a/pom.xml b/pom.xml index 324f6129db..13b866b968 100644 --- a/pom.xml +++ b/pom.xml @@ -329,6 +329,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin @@ -600,6 +601,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin @@ -993,6 +995,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin @@ -1045,6 +1048,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin @@ -1312,6 +1316,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin @@ -1544,6 +1549,7 @@ parent-boot-2 parent-spring-4 parent-spring-5 + parent-spring-5-1 parent-java parent-kotlin diff --git a/spring-dispatcher-servlet/pom.xml b/spring-dispatcher-servlet/pom.xml index 7ac291740e..ea5eb8845e 100644 --- a/spring-dispatcher-servlet/pom.xml +++ b/spring-dispatcher-servlet/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-spring-5 + parent-spring-5-1 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-5-1 diff --git a/spring-mvc-forms-jsp/pom.xml b/spring-mvc-forms-jsp/pom.xml index 5536314086..80818f4e88 100644 --- a/spring-mvc-forms-jsp/pom.xml +++ b/spring-mvc-forms-jsp/pom.xml @@ -11,9 +11,9 @@ com.baeldung - parent-spring-5 + parent-spring-5-1 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-5-1 diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index 9d3e0ca1b2..b0b187ee84 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -8,10 +8,10 @@ war - parent-spring-5 + parent-spring-5-1 com.baeldung 0.0.1-SNAPSHOT - ../parent-spring-5 + ../parent-spring-5-1 diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml index 65fa4339d6..087ffea46d 100644 --- a/spring-mvc-simple/pom.xml +++ b/spring-mvc-simple/pom.xml @@ -154,25 +154,6 @@ ${deploy-path} - - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - default-test - - true - - - - - - org.junit.platform - junit-platform-surefire-provider - ${junit.platform.version} - - - spring-mvc-simple diff --git a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java index a9c7e0cf15..082477c98c 100644 --- a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java +++ b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java @@ -1,7 +1,6 @@ package com.baeldung.spring; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; diff --git a/spring-security-rest-basic-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java b/spring-security-rest-basic-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java index 5e15648e9b..3ed0bc82b7 100644 --- a/spring-security-rest-basic-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java +++ b/spring-security-rest-basic-auth/src/main/java/org/baeldung/client/RestTemplateFactory.java @@ -4,7 +4,7 @@ import org.apache.http.HttpHost; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.support.BasicAuthorizationInterceptor; +import org.springframework.http.client.support.BasicAuthenticationInterceptor; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -38,7 +38,7 @@ public class RestTemplateFactory implements FactoryBean, Initializ HttpHost host = new HttpHost("localhost", 8082, "http"); final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host); restTemplate = new RestTemplate(requestFactory); - restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user1", "user1Pass")); + restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("user1", "user1Pass")); } } \ No newline at end of file diff --git a/spring-security-rest-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java b/spring-security-rest-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java index 2305a7b6c2..5876e1307b 100644 --- a/spring-security-rest-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java +++ b/spring-security-rest-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java @@ -8,7 +8,6 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @EnableWebMvc diff --git a/spring-security-rest-basic-auth/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-security-rest-basic-auth/src/test/java/org/baeldung/SpringContextIntegrationTest.java index 6cf624c179..31b3f2be87 100644 --- a/spring-security-rest-basic-auth/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-security-rest-basic-auth/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -6,7 +6,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration({ "/WebSecurityConfig.xml" }) +@ContextConfiguration({ "/webSecurityConfig.xml" }) public class SpringContextIntegrationTest { @Test diff --git a/spring-security-rest/src/test/java/org/baeldung/web/FooLiveTest.java b/spring-security-rest/src/test/java/org/baeldung/web/FooLiveTest.java index 0a53da674a..86beeb46a9 100644 --- a/spring-security-rest/src/test/java/org/baeldung/web/FooLiveTest.java +++ b/spring-security-rest/src/test/java/org/baeldung/web/FooLiveTest.java @@ -29,7 +29,7 @@ public class FooLiveTest { // } // return RestAssured.given().cookie("JSESSIONID", cookie); return RestAssured.given() - .auth() + .auth().preemptive() .basic("user", "userPass"); } From cde1d1c7ad72c3d3608b97aa45c933b4ded0b86b Mon Sep 17 00:00:00 2001 From: geroza Date: Tue, 8 Jan 2019 17:17:28 -0200 Subject: [PATCH 41/70] Fixed usage of deprecated GzipResourceResolver in spring-static-resources added back spring-version modification in module that hasnt been worked yet cleaned unused classes --- persistence-modules/spring-data-mongodb/pom.xml | 1 + .../src/main/java/com/baeldung/spring/MvcConfig.java | 1 - .../src/main/java/org/baeldung/spring/MvcConfig.java | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-modules/spring-data-mongodb/pom.xml b/persistence-modules/spring-data-mongodb/pom.xml index 4da0526ca6..86e4b275e7 100644 --- a/persistence-modules/spring-data-mongodb/pom.xml +++ b/persistence-modules/spring-data-mongodb/pom.xml @@ -96,6 +96,7 @@ + 5.1.0.RELEASE 2.1.2.RELEASE 4.1.4 1.1.3 diff --git a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java index 082477c98c..629e203b56 100644 --- a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java +++ b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java @@ -1,7 +1,6 @@ package com.baeldung.spring; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; diff --git a/spring-static-resources/src/main/java/org/baeldung/spring/MvcConfig.java b/spring-static-resources/src/main/java/org/baeldung/spring/MvcConfig.java index dbc548e028..7bd03617be 100644 --- a/spring-static-resources/src/main/java/org/baeldung/spring/MvcConfig.java +++ b/spring-static-resources/src/main/java/org/baeldung/spring/MvcConfig.java @@ -18,7 +18,7 @@ import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.CookieLocaleResolver; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; -import org.springframework.web.servlet.resource.GzipResourceResolver; +import org.springframework.web.servlet.resource.EncodedResourceResolver; import org.springframework.web.servlet.resource.PathResourceResolver; import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @@ -57,10 +57,10 @@ public class MvcConfig implements WebMvcConfigurer { public void addResourceHandlers(ResourceHandlerRegistry registry) { // For examples using Spring 4.1.0 if ((env.getProperty("resource.handler.conf")).equals("4.1.0")) { - registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(3600).resourceChain(true).addResolver(new GzipResourceResolver()).addResolver(new PathResourceResolver()); + registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(3600).resourceChain(true).addResolver(new EncodedResourceResolver()).addResolver(new PathResourceResolver()); registry.addResourceHandler("/resources/**").addResourceLocations("/resources/", "classpath:/other-resources/").setCachePeriod(3600).resourceChain(true).addResolver(new PathResourceResolver()); registry.addResourceHandler("/files/**").addResourceLocations("file:/Users/Elena/").setCachePeriod(3600).resourceChain(true).addResolver(new PathResourceResolver()); - registry.addResourceHandler("/other-files/**").addResourceLocations("file:/Users/Elena/").setCachePeriod(3600).resourceChain(true).addResolver(new GzipResourceResolver()); + registry.addResourceHandler("/other-files/**").addResourceLocations("file:/Users/Elena/").setCachePeriod(3600).resourceChain(true).addResolver(new EncodedResourceResolver()); } // For examples using Spring 4.0.7 else if ((env.getProperty("resource.handler.conf")).equals("4.0.7")) { From 74df0da304af2152a45ecf60a5f65ae77e0bc474 Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 12:28:21 -0200 Subject: [PATCH 42/70] fixed removed import by mistake --- .../src/main/java/com/baeldung/spring/MvcConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java index 629e203b56..082477c98c 100644 --- a/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java +++ b/spring-security-mvc-login/src/main/java/com/baeldung/spring/MvcConfig.java @@ -1,6 +1,7 @@ package com.baeldung.spring; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; From 63258737ceb25dd435d3437920b2e8d8fff709aa Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 13:33:39 -0200 Subject: [PATCH 43/70] modified readme file to kick off travis build --- ethereum/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ethereum/README.md b/ethereum/README.md index d06ca09636..0c7ae3d4d2 100644 --- a/ethereum/README.md +++ b/ethereum/README.md @@ -4,3 +4,4 @@ - [Introduction to EthereumJ](http://www.baeldung.com/ethereumj) - [Creating and Deploying Smart Contracts with Solidity](http://www.baeldung.com/smart-contracts-ethereum-solidity) - [Lightweight Ethereum Clients Using Web3j](http://www.baeldung.com/web3j) + From 04a4c339b767267739690c633901f911a621b46f Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 14:53:44 -0200 Subject: [PATCH 44/70] change to kick off build --- ethereum/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ethereum/README.md b/ethereum/README.md index 0c7ae3d4d2..d06ca09636 100644 --- a/ethereum/README.md +++ b/ethereum/README.md @@ -4,4 +4,3 @@ - [Introduction to EthereumJ](http://www.baeldung.com/ethereumj) - [Creating and Deploying Smart Contracts with Solidity](http://www.baeldung.com/smart-contracts-ethereum-solidity) - [Lightweight Ethereum Clients Using Web3j](http://www.baeldung.com/web3j) - From 39bfa04d11d34b8b3fe98deb43936854eaea9fcf Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 23:51:39 -0200 Subject: [PATCH 45/70] change to kick off build --- ethereum/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ethereum/README.md b/ethereum/README.md index d06ca09636..7accb4cd53 100644 --- a/ethereum/README.md +++ b/ethereum/README.md @@ -4,3 +4,4 @@ - [Introduction to EthereumJ](http://www.baeldung.com/ethereumj) - [Creating and Deploying Smart Contracts with Solidity](http://www.baeldung.com/smart-contracts-ethereum-solidity) - [Lightweight Ethereum Clients Using Web3j](http://www.baeldung.com/web3j) + \ No newline at end of file From 57228dfc6b9ec1af0658f9b616056708c070bb28 Mon Sep 17 00:00:00 2001 From: Rodolfo Felipe Date: Wed, 9 Jan 2019 22:29:44 -0400 Subject: [PATCH 46/70] 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 47/70] 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 bb966c8e1461083cc6d3617242bc7cf9ac7c0fac Mon Sep 17 00:00:00 2001 From: dupirefr Date: Thu, 10 Jan 2019 08:51:53 +0100 Subject: [PATCH 48/70] [BAEL-2531] Directories creation tests --- .../directories/NewDirectoryUnitTest.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 core-java-io/src/test/java/com/baeldung/directories/NewDirectoryUnitTest.java diff --git a/core-java-io/src/test/java/com/baeldung/directories/NewDirectoryUnitTest.java b/core-java-io/src/test/java/com/baeldung/directories/NewDirectoryUnitTest.java new file mode 100644 index 0000000000..e0111c2702 --- /dev/null +++ b/core-java-io/src/test/java/com/baeldung/directories/NewDirectoryUnitTest.java @@ -0,0 +1,100 @@ +package com.baeldung.directories; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class NewDirectoryUnitTest { + + private static final File TEMP_DIRECTORY = new File(System.getProperty("java.io.tmpdir")); + + @Before + public void beforeEach() { + File newDirectory = new File(TEMP_DIRECTORY, "new_directory"); + File nestedInNewDirectory = new File(newDirectory, "nested_directory"); + File existingDirectory = new File(TEMP_DIRECTORY, "existing_directory"); + File existingNestedDirectory = new File(existingDirectory, "existing_nested_directory"); + File nestedInExistingDirectory = new File(existingDirectory, "nested_directory"); + + nestedInNewDirectory.delete(); + newDirectory.delete(); + nestedInExistingDirectory.delete(); + existingDirectory.mkdir(); + existingNestedDirectory.mkdir(); + } + + @Test + public void givenUnexistingDirectory_whenMkdir_thenTrue() { + File newDirectory = new File(TEMP_DIRECTORY, "new_directory"); + assertFalse(newDirectory.exists()); + + boolean directoryCreated = newDirectory.mkdir(); + + assertTrue(directoryCreated); + } + + @Test + public void givenExistingDirectory_whenMkdir_thenFalse() { + File newDirectory = new File(TEMP_DIRECTORY, "new_directory"); + newDirectory.mkdir(); + assertTrue(newDirectory.exists()); + + boolean directoryCreated = newDirectory.mkdir(); + + assertFalse(directoryCreated); + } + + @Test + public void givenUnexistingNestedDirectories_whenMkdir_thenFalse() { + File newDirectory = new File(TEMP_DIRECTORY, "new_directory"); + File nestedDirectory = new File(newDirectory, "nested_directory"); + assertFalse(newDirectory.exists()); + assertFalse(nestedDirectory.exists()); + + boolean directoriesCreated = nestedDirectory.mkdir(); + + assertFalse(directoriesCreated); + } + + @Test + public void givenUnexistingNestedDirectories_whenMkdirs_thenTrue() { + File newDirectory = new File(TEMP_DIRECTORY, "new_directory"); + File nestedDirectory = new File(newDirectory, "nested_directory"); + assertFalse(newDirectory.exists()); + assertFalse(nestedDirectory.exists()); + + boolean directoriesCreated = nestedDirectory.mkdirs(); + + assertTrue(directoriesCreated); + } + + @Test + public void givenExistingParentDirectories_whenMkdirs_thenTrue() { + File newDirectory = new File(TEMP_DIRECTORY, "existing_directory"); + newDirectory.mkdir(); + File nestedDirectory = new File(newDirectory, "nested_directory"); + assertTrue(newDirectory.exists()); + assertFalse(nestedDirectory.exists()); + + boolean directoriesCreated = nestedDirectory.mkdirs(); + + assertTrue(directoriesCreated); + } + + @Test + public void givenExistingNestedDirectories_whenMkdirs_thenFalse() { + File existingDirectory = new File(TEMP_DIRECTORY, "existing_directory"); + File existingNestedDirectory = new File(existingDirectory, "existing_nested_directory"); + assertTrue(existingDirectory.exists()); + assertTrue(existingNestedDirectory.exists()); + + boolean directoriesCreated = existingNestedDirectory.mkdirs(); + + assertFalse(directoriesCreated); + } + +} From 9b550e6554f0432f9e93a1f20273398909f17369 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 10 Jan 2019 15:00:38 +0400 Subject: [PATCH 49/70] localdate converter --- .../com/baeldung/util/LocalDateConverter.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java new file mode 100644 index 0000000000..341492d1fd --- /dev/null +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java @@ -0,0 +1,25 @@ +package com.baeldung.util; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import java.sql.Date; +import java.time.LocalDate; +import java.util.Optional; + +@Converter(autoApply = true) +public class LocalDateConverter implements AttributeConverter { + + @Override + public Date convertToDatabaseColumn(LocalDate localDateTime) { + return Optional.ofNullable(localDateTime) + .map(Date::valueOf) + .orElse(null); + } + + @Override + public LocalDate convertToEntityAttribute(Date timestamp) { + return Optional.ofNullable(timestamp) + .map(Date::toLocalDate) + .orElse(null); + } +} \ No newline at end of file From 6202b7caab30ba5db67e992925efa60c21c2a881 Mon Sep 17 00:00:00 2001 From: mherbaghinyan Date: Thu, 10 Jan 2019 15:18:21 +0400 Subject: [PATCH 50/70] localdate converter --- .../main/java/com/baeldung/util/LocalDateConverter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java index 341492d1fd..00fd378b05 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java +++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/util/LocalDateConverter.java @@ -10,15 +10,15 @@ import java.util.Optional; public class LocalDateConverter implements AttributeConverter { @Override - public Date convertToDatabaseColumn(LocalDate localDateTime) { - return Optional.ofNullable(localDateTime) + public Date convertToDatabaseColumn(LocalDate localDate) { + return Optional.ofNullable(localDate) .map(Date::valueOf) .orElse(null); } @Override - public LocalDate convertToEntityAttribute(Date timestamp) { - return Optional.ofNullable(timestamp) + public LocalDate convertToEntityAttribute(Date date) { + return Optional.ofNullable(date) .map(Date::toLocalDate) .orElse(null); } From 1ca15e59190955a5bb53c1466d7aac68a8d79859 Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 12:23:10 -0200 Subject: [PATCH 51/70] Migrated modules using parent-spring-5: ethereum persistence-modules/spring-data-elasticsearch persistence-modules/spring-data-mongodb spring-dispatcher-servlet spring-mvc-forms-jsp spring-mvc-java --- ethereum/pom.xml | 15 ++--- .../spring-data-elasticsearch/pom.xml | 4 +- .../ElasticSearchManualTest.java | 7 ++ ...ionTest.java => GeoQueriesManualTest.java} | 10 ++- ...Test.java => ElasticSearchManualTest.java} | 9 ++- ...java => ElasticSearchQueryManualTest.java} | 9 ++- ...Test.java => SpringContextManualTest.java} | 8 ++- .../spring-data-mongodb/pom.xml | 5 +- .../aggregation/ZipsAggregationLiveTest.java | 6 ++ .../com/baeldung/gridfs/GridFSLiveTest.java | 6 ++ .../mongotemplate/DocumentQueryLiveTest.java | 6 ++ .../MongoTemplateProjectionLiveTest.java | 6 ++ .../MongoTemplateQueryLiveTest.java | 6 ++ .../repository/ActionRepositoryLiveTest.java | 6 ++ .../repository/BaseQueryLiveTest.java | 6 ++ .../baeldung/repository/DSLQueryLiveTest.java | 8 ++- .../repository/JSONQueryLiveTest.java | 6 ++ .../repository/QueryMethodsLiveTest.java | 6 ++ .../repository/UserRepositoryLiveTest.java | 6 ++ .../UserRepositoryProjectionLiveTest.java | 6 ++ .../MongoTransactionReactiveLiveTest.java | 6 ++ .../MongoTransactionTemplateLiveTest.java | 6 ++ .../MongoTransactionalLiveTest.java | 6 ++ spring-4/README.md | 1 + spring-4/pom.xml | 16 +++++ .../com/baeldung/flips/ApplicationConfig.java | 8 ++- .../com/baeldung/jsonp/JsonPApplication.java | 27 ++++++++ .../com/baeldung/jsonp/model/Company.java | 38 +++++++++++ .../web/controller/CompanyController.java | 27 ++++++++ .../jsonp/web/controller/IndexController.java | 13 ++++ .../advice/JsonpControllerAdvice.java | 5 +- .../src/main/resources/application.properties | 2 +- .../resources/jsonp-application.properties | 2 + .../src/main/webapp/WEB-INF/jsp/index.jsp | 66 +++++++++++++++++++ spring-dispatcher-servlet/pom.xml | 4 +- spring-mvc-forms-jsp/pom.xml | 4 +- spring-mvc-java/README.md | 1 - spring-mvc-java/pom.xml | 20 +++++- .../web/controller/CompanyController.java | 13 ---- .../config/HandlerMappingDefaultConfig.java | 9 +-- .../com/baeldung/htmlunit/TestConfig.java | 1 - .../ClassValidationMvcIntegrationTest.java | 1 - .../GreetControllerIntegrationTest.java | 1 - 43 files changed, 366 insertions(+), 52 deletions(-) rename persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/{GeoQueriesIntegrationTest.java => GeoQueriesManualTest.java} (97%) rename persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/{ElasticSearchIntegrationTest.java => ElasticSearchManualTest.java} (97%) rename persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/{ElasticSearchQueryIntegrationTest.java => ElasticSearchQueryManualTest.java} (98%) rename persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/{SpringContextIntegrationTest.java => SpringContextManualTest.java} (77%) create mode 100644 spring-4/src/main/java/com/baeldung/jsonp/JsonPApplication.java create mode 100644 spring-4/src/main/java/com/baeldung/jsonp/model/Company.java create mode 100644 spring-4/src/main/java/com/baeldung/jsonp/web/controller/CompanyController.java create mode 100644 spring-4/src/main/java/com/baeldung/jsonp/web/controller/IndexController.java rename {spring-mvc-java/src/main/java/com/baeldung => spring-4/src/main/java/com/baeldung/jsonp}/web/controller/advice/JsonpControllerAdvice.java (53%) create mode 100644 spring-4/src/main/resources/jsonp-application.properties create mode 100644 spring-4/src/main/webapp/WEB-INF/jsp/index.jsp diff --git a/ethereum/pom.xml b/ethereum/pom.xml index 334840edaf..c7f82eaf22 100644 --- a/ethereum/pom.xml +++ b/ethereum/pom.xml @@ -7,10 +7,10 @@ ethereum - parent-spring-5-1 + parent-spring-5 com.baeldung 0.0.1-SNAPSHOT - ../parent-spring-5-1 + ../parent-spring-5 @@ -37,17 +37,17 @@ org.springframework spring-core - ${springframework.version} + ${spring.version} org.springframework spring-web - ${springframework.version} + ${spring.version} org.springframework spring-webmvc - ${springframework.version} + ${spring.version} @@ -123,12 +123,12 @@ org.springframework spring-context - ${springframework.version} + ${spring.version} org.springframework spring-test - ${springframework.version} + ${spring.version} test @@ -212,7 +212,6 @@ 8.5.4 1.5.0-RELEASE 3.3.1 - 5.0.5.RELEASE 1.5.6.RELEASE 2.21.0 2.9.7 diff --git a/persistence-modules/spring-data-elasticsearch/pom.xml b/persistence-modules/spring-data-elasticsearch/pom.xml index c5ad9b64f9..ee9e71a1cb 100644 --- a/persistence-modules/spring-data-elasticsearch/pom.xml +++ b/persistence-modules/spring-data-elasticsearch/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-spring-5-1 + parent-spring-5 0.0.1-SNAPSHOT - ../../parent-spring-5-1 + ../../parent-spring-5 diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java index fbf4e5ab99..e43dcdf43e 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java @@ -30,6 +30,13 @@ import org.junit.Test; import com.alibaba.fastjson.JSON; +/** + * + * This Manual test requires: + * * Elasticsearch instance running on host + * * with cluster name = elasticsearch + * + */ public class ElasticSearchManualTest { private List listOfPersons = new ArrayList<>(); private Client client = null; diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesIntegrationTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java similarity index 97% rename from persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesIntegrationTest.java rename to persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java index 1f55379418..f9a42050b6 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesIntegrationTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesManualTest.java @@ -31,9 +31,17 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.baeldung.spring.data.es.config.Config; import com.vividsolutions.jts.geom.Coordinate; +/** + * + * This Manual test requires: + * * Elasticsearch instance running on host + * * with cluster name = elasticsearch + * * and further configurations + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) -public class GeoQueriesIntegrationTest { +public class GeoQueriesManualTest { private static final String WONDERS_OF_WORLD = "wonders-of-world"; private static final String WONDERS = "Wonders"; diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java similarity index 97% rename from persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java rename to persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java index 6ecb11cdbe..bed2e2ff25 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchManualTest.java @@ -27,9 +27,16 @@ import com.baeldung.spring.data.es.model.Article; import com.baeldung.spring.data.es.model.Author; import com.baeldung.spring.data.es.service.ArticleService; +/** + * + * This Manual test requires: + * * Elasticsearch instance running on host + * * with cluster name = elasticsearch + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) -public class ElasticSearchIntegrationTest { +public class ElasticSearchManualTest { @Autowired private ElasticsearchTemplate elasticsearchTemplate; diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java similarity index 98% rename from persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java rename to persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java index 2348c49830..5e24d8398c 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryManualTest.java @@ -41,9 +41,16 @@ import com.baeldung.spring.data.es.model.Article; import com.baeldung.spring.data.es.model.Author; import com.baeldung.spring.data.es.service.ArticleService; +/** + * + * This Manual test requires: + * * Elasticsearch instance running on host + * * with cluster name = elasticsearch + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) -public class ElasticSearchQueryIntegrationTest { +public class ElasticSearchQueryManualTest { @Autowired private ElasticsearchTemplate elasticsearchTemplate; diff --git a/persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextManualTest.java similarity index 77% rename from persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextManualTest.java index 6f45039c96..c6f095eae9 100644 --- a/persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/persistence-modules/spring-data-elasticsearch/src/test/java/org/baeldung/SpringContextManualTest.java @@ -7,9 +7,15 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.baeldung.spring.data.es.config.Config; +/** + * + * This Manual test requires: + * * Elasticsearch instance running on host + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) -public class SpringContextIntegrationTest { +public class SpringContextManualTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/persistence-modules/spring-data-mongodb/pom.xml b/persistence-modules/spring-data-mongodb/pom.xml index 86e4b275e7..c1faf72103 100644 --- a/persistence-modules/spring-data-mongodb/pom.xml +++ b/persistence-modules/spring-data-mongodb/pom.xml @@ -6,9 +6,9 @@ com.baeldung - parent-spring-5-1 + parent-spring-5 0.0.1-SNAPSHOT - ../../parent-spring-5-1 + ../../parent-spring-5 @@ -96,7 +96,6 @@ - 5.1.0.RELEASE 2.1.2.RELEASE 4.1.4 1.1.3 diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/aggregation/ZipsAggregationLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/aggregation/ZipsAggregationLiveTest.java index 1da50d7cb4..1002dc79eb 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/aggregation/ZipsAggregationLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/aggregation/ZipsAggregationLiveTest.java @@ -44,6 +44,12 @@ import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class ZipsAggregationLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/gridfs/GridFSLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/gridfs/GridFSLiveTest.java index 3a88a1e654..d25b9ece4f 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/gridfs/GridFSLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/gridfs/GridFSLiveTest.java @@ -31,6 +31,12 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.client.gridfs.model.GridFSFile; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @ContextConfiguration("file:src/main/resources/mongoConfig.xml") @RunWith(SpringJUnit4ClassRunner.class) public class GridFSLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/DocumentQueryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/DocumentQueryLiveTest.java index d05bde0f1b..e5e4a188ec 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/DocumentQueryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/DocumentQueryLiveTest.java @@ -24,6 +24,12 @@ import com.baeldung.config.MongoConfig; import com.baeldung.model.EmailAddress; import com.baeldung.model.User; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class DocumentQueryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateProjectionLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateProjectionLiveTest.java index 309f14e995..9e12997c67 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateProjectionLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateProjectionLiveTest.java @@ -16,6 +16,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SimpleMongoConfig.class) public class MongoTemplateProjectionLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateQueryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateQueryLiveTest.java index fc78921b75..4f62f0d7a7 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateQueryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/mongotemplate/MongoTemplateQueryLiveTest.java @@ -27,6 +27,12 @@ import com.baeldung.config.MongoConfig; import com.baeldung.model.EmailAddress; import com.baeldung.model.User; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class MongoTemplateQueryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/ActionRepositoryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/ActionRepositoryLiveTest.java index 096015ca0a..79648f1a20 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/ActionRepositoryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/ActionRepositoryLiveTest.java @@ -15,6 +15,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.time.ZoneOffset; import java.time.ZonedDateTime; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class ActionRepositoryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/BaseQueryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/BaseQueryLiveTest.java index e4849181e5..c94bb2ae4c 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/BaseQueryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/BaseQueryLiveTest.java @@ -7,6 +7,12 @@ import org.junit.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoOperations; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ public class BaseQueryLiveTest { @Autowired diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/DSLQueryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/DSLQueryLiveTest.java index f87ca5cbb5..0ccf677b3e 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/DSLQueryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/DSLQueryLiveTest.java @@ -15,8 +15,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.querydsl.core.types.Predicate; - - +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class DSLQueryLiveTest extends BaseQueryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/JSONQueryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/JSONQueryLiveTest.java index 4e99c0b140..3a99407350 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/JSONQueryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/JSONQueryLiveTest.java @@ -12,6 +12,12 @@ import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class JSONQueryLiveTest extends BaseQueryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/QueryMethodsLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/QueryMethodsLiveTest.java index 47e67a6b4c..ef8ce10dd1 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/QueryMethodsLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/QueryMethodsLiveTest.java @@ -12,6 +12,12 @@ import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class QueryMethodsLiveTest extends BaseQueryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryLiveTest.java index 901610e42d..dd7215af7e 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryLiveTest.java @@ -23,6 +23,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.baeldung.config.MongoConfig; import com.baeldung.model.User; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class UserRepositoryLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryProjectionLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryProjectionLiveTest.java index 80f4275794..8972246041 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryProjectionLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/repository/UserRepositoryProjectionLiveTest.java @@ -13,6 +13,12 @@ import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class UserRepositoryProjectionLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionReactiveLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionReactiveLiveTest.java index 70908552fe..3fc8dcf977 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionReactiveLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionReactiveLiveTest.java @@ -12,6 +12,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.baeldung.config.MongoReactiveConfig; import com.baeldung.model.User; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoReactiveConfig.class) public class MongoTransactionReactiveLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java index 20ac6974bc..53b2c7a0e7 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionTemplateLiveTest.java @@ -24,6 +24,12 @@ import org.springframework.transaction.support.TransactionTemplate; import com.baeldung.config.MongoConfig; import com.baeldung.model.User; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) public class MongoTransactionTemplateLiveTest { diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java index 0cf86aa43e..bafcd770ec 100644 --- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java @@ -24,6 +24,12 @@ import com.baeldung.model.User; import com.baeldung.repository.UserRepository; import com.mongodb.MongoCommandException; +/** + * + * This test requires: + * * mongodb instance running on the environment + * + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoConfig.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) diff --git a/spring-4/README.md b/spring-4/README.md index 402557eb41..57cb8c3eeb 100644 --- a/spring-4/README.md +++ b/spring-4/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [A Guide to Flips for Spring](http://www.baeldung.com/flips-spring) - [Configuring a Hikari Connection Pool with Spring Boot](https://www.baeldung.com/spring-boot-hikari) +- [Spring JSON-P with Jackson](http://www.baeldung.com/spring-jackson-jsonp) diff --git a/spring-4/pom.xml b/spring-4/pom.xml index 78939bba95..60f1555d8f 100644 --- a/spring-4/pom.xml +++ b/spring-4/pom.xml @@ -52,6 +52,21 @@ provided + + javax.servlet + jstl + + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.apache.tomcat.embed + tomcat-embed-jasper + provided + @@ -71,6 +86,7 @@ + com.baeldung.flips.ApplicationConfig 1.0.1 1.16.18 1.4.197 diff --git a/spring-4/src/main/java/com/baeldung/flips/ApplicationConfig.java b/spring-4/src/main/java/com/baeldung/flips/ApplicationConfig.java index 7001aeb991..1bd6ffa336 100644 --- a/spring-4/src/main/java/com/baeldung/flips/ApplicationConfig.java +++ b/spring-4/src/main/java/com/baeldung/flips/ApplicationConfig.java @@ -3,9 +3,15 @@ package com.baeldung.flips; import org.flips.describe.config.FlipWebContextConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.annotation.Import; -@SpringBootApplication +@SpringBootApplication(exclude = { + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + HibernateJpaAutoConfiguration.class }) @Import(FlipWebContextConfiguration.class) public class ApplicationConfig { diff --git a/spring-4/src/main/java/com/baeldung/jsonp/JsonPApplication.java b/spring-4/src/main/java/com/baeldung/jsonp/JsonPApplication.java new file mode 100644 index 0000000000..a8f3c0e102 --- /dev/null +++ b/spring-4/src/main/java/com/baeldung/jsonp/JsonPApplication.java @@ -0,0 +1,27 @@ +package com.baeldung.jsonp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication(exclude = { + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + HibernateJpaAutoConfiguration.class }) +@PropertySource("classpath:jsonp-application.properties") +public class JsonPApplication extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(JsonPApplication.class); + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(JsonPApplication.class, args); + } +} diff --git a/spring-4/src/main/java/com/baeldung/jsonp/model/Company.java b/spring-4/src/main/java/com/baeldung/jsonp/model/Company.java new file mode 100644 index 0000000000..b11a216e52 --- /dev/null +++ b/spring-4/src/main/java/com/baeldung/jsonp/model/Company.java @@ -0,0 +1,38 @@ +package com.baeldung.jsonp.model; + +public class Company { + + private long id; + private String name; + + public Company() { + super(); + } + + public Company(final long id, final String name) { + this.id = id; + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(final long id) { + this.id = id; + } + + @Override + public String toString() { + return "Company [id=" + id + ", name=" + name + "]"; + } + +} diff --git a/spring-4/src/main/java/com/baeldung/jsonp/web/controller/CompanyController.java b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/CompanyController.java new file mode 100644 index 0000000000..8710359365 --- /dev/null +++ b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/CompanyController.java @@ -0,0 +1,27 @@ +package com.baeldung.jsonp.web.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.baeldung.jsonp.model.Company; + +@Controller +public class CompanyController { + + @RequestMapping(value = "/companyResponseBody", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Company getCompanyResponseBody() { + final Company company = new Company(2, "ABC"); + return company; + } + + @RequestMapping(value = "/companyResponseEntity", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getCompanyResponseEntity() { + final Company company = new Company(3, "123"); + return new ResponseEntity(company, HttpStatus.OK); + } +} diff --git a/spring-4/src/main/java/com/baeldung/jsonp/web/controller/IndexController.java b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/IndexController.java new file mode 100644 index 0000000000..8469e19458 --- /dev/null +++ b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/IndexController.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonp.web.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class IndexController { + + @RequestMapping() + public String retrieveIndex() { + return "index"; + } +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/advice/JsonpControllerAdvice.java b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/advice/JsonpControllerAdvice.java similarity index 53% rename from spring-mvc-java/src/main/java/com/baeldung/web/controller/advice/JsonpControllerAdvice.java rename to spring-4/src/main/java/com/baeldung/jsonp/web/controller/advice/JsonpControllerAdvice.java index 7b2c6870df..be7c65cb1e 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/advice/JsonpControllerAdvice.java +++ b/spring-4/src/main/java/com/baeldung/jsonp/web/controller/advice/JsonpControllerAdvice.java @@ -1,8 +1,11 @@ -package com.baeldung.web.controller.advice; +package com.baeldung.jsonp.web.controller.advice; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; +// AbstractJsonpResponseBodyAdvice was deprecated in favor of configuring CORS properly +// We still want to cover the usage of JSON-P in our articles, therefore we don't care that it was deprecated. +@SuppressWarnings("deprecation") @ControllerAdvice public class JsonpControllerAdvice extends AbstractJsonpResponseBodyAdvice { diff --git a/spring-4/src/main/resources/application.properties b/spring-4/src/main/resources/application.properties index 274896be15..e67700b7be 100644 --- a/spring-4/src/main/resources/application.properties +++ b/spring-4/src/main/resources/application.properties @@ -2,4 +2,4 @@ feature.foo.by.id=Y feature.new.foo=Y last.active.after=2018-03-14T00:00:00Z first.active.after=2999-03-15T00:00:00Z -logging.level.org.flips=info \ No newline at end of file +logging.level.org.flips=info diff --git a/spring-4/src/main/resources/jsonp-application.properties b/spring-4/src/main/resources/jsonp-application.properties new file mode 100644 index 0000000000..94e7fcc026 --- /dev/null +++ b/spring-4/src/main/resources/jsonp-application.properties @@ -0,0 +1,2 @@ +spring.mvc.view.prefix=/WEB-INF/jsp/ +spring.mvc.view.suffix=.jsp diff --git a/spring-4/src/main/webapp/WEB-INF/jsp/index.jsp b/spring-4/src/main/webapp/WEB-INF/jsp/index.jsp new file mode 100644 index 0000000000..fa5498c966 --- /dev/null +++ b/spring-4/src/main/webapp/WEB-INF/jsp/index.jsp @@ -0,0 +1,66 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1" %> + + + + + Company Data + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/spring-dispatcher-servlet/pom.xml b/spring-dispatcher-servlet/pom.xml index ea5eb8845e..7ac291740e 100644 --- a/spring-dispatcher-servlet/pom.xml +++ b/spring-dispatcher-servlet/pom.xml @@ -10,9 +10,9 @@ com.baeldung - parent-spring-5-1 + parent-spring-5 0.0.1-SNAPSHOT - ../parent-spring-5-1 + ../parent-spring-5 diff --git a/spring-mvc-forms-jsp/pom.xml b/spring-mvc-forms-jsp/pom.xml index 80818f4e88..5536314086 100644 --- a/spring-mvc-forms-jsp/pom.xml +++ b/spring-mvc-forms-jsp/pom.xml @@ -11,9 +11,9 @@ com.baeldung - parent-spring-5-1 + parent-spring-5 0.0.1-SNAPSHOT - ../parent-spring-5-1 + ../parent-spring-5 diff --git a/spring-mvc-java/README.md b/spring-mvc-java/README.md index c7fcbd400b..851a3689ab 100644 --- a/spring-mvc-java/README.md +++ b/spring-mvc-java/README.md @@ -11,7 +11,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Introduction to Advice Types in Spring](http://www.baeldung.com/spring-aop-advice-tutorial) - [A Guide to the ViewResolver in Spring MVC](http://www.baeldung.com/spring-mvc-view-resolver-tutorial) - [Integration Testing in Spring](http://www.baeldung.com/integration-testing-in-spring) -- [Spring JSON-P with Jackson](http://www.baeldung.com/spring-jackson-jsonp) - [A Quick Guide to Spring MVC Matrix Variables](http://www.baeldung.com/spring-mvc-matrix-variables) - [Intro to WebSockets with Spring](http://www.baeldung.com/websockets-spring) - [File Upload with Spring MVC](http://www.baeldung.com/spring-file-upload) diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index b0b187ee84..562df30318 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -8,10 +8,10 @@ war - parent-spring-5-1 + parent-spring-5 com.baeldung 0.0.1-SNAPSHOT - ../parent-spring-5-1 + ../parent-spring-5 @@ -60,6 +60,12 @@ commons-fileupload commons-fileupload ${commons-fileupload.version} + + + commons-io + commons-io + + net.sourceforge.htmlunit @@ -70,8 +76,17 @@ commons-logging commons-logging + + commons-io + commons-io + + + commons-io + commons-io + ${commons-io.version} + @@ -255,6 +270,7 @@ 19.0 3.5 1.3.2 + 2.5 2.2.0 diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/CompanyController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/CompanyController.java index e92abfdc47..af1e729c13 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/CompanyController.java +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/CompanyController.java @@ -60,17 +60,4 @@ public class CompanyController { result.put("name", name); return new ResponseEntity<>(result, HttpStatus.OK); } - - @RequestMapping(value = "/companyResponseBody", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public Company getCompanyResponseBody() { - final Company company = new Company(2, "ABC"); - return company; - } - - @RequestMapping(value = "/companyResponseEntity", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getCompanyResponseEntity() { - final Company company = new Company(3, "123"); - return new ResponseEntity(company, HttpStatus.OK); - } } diff --git a/spring-mvc-java/src/test/java/com/baeldung/config/HandlerMappingDefaultConfig.java b/spring-mvc-java/src/test/java/com/baeldung/config/HandlerMappingDefaultConfig.java index 9190d07d6b..d3a329a387 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/config/HandlerMappingDefaultConfig.java +++ b/spring-mvc-java/src/test/java/com/baeldung/config/HandlerMappingDefaultConfig.java @@ -1,15 +1,10 @@ package com.baeldung.config; -import com.baeldung.web.controller.handlermapping.BeanNameHandlerMappingController; -import com.baeldung.web.controller.handlermapping.SimpleUrlMappingController; -import com.baeldung.web.controller.handlermapping.WelcomeController; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import java.util.HashMap; -import java.util.Map; +import com.baeldung.web.controller.handlermapping.BeanNameHandlerMappingController; +import com.baeldung.web.controller.handlermapping.WelcomeController; @Configuration diff --git a/spring-mvc-java/src/test/java/com/baeldung/htmlunit/TestConfig.java b/spring-mvc-java/src/test/java/com/baeldung/htmlunit/TestConfig.java index 5b86b59095..529879fada 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/htmlunit/TestConfig.java +++ b/spring-mvc-java/src/test/java/com/baeldung/htmlunit/TestConfig.java @@ -9,7 +9,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.thymeleaf.spring4.SpringTemplateEngine; import org.thymeleaf.spring4.view.ThymeleafViewResolver; import org.thymeleaf.templateresolver.ServletContextTemplateResolver; diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/ClassValidationMvcIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/ClassValidationMvcIntegrationTest.java index a86f71011c..2cd225a775 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/web/controller/ClassValidationMvcIntegrationTest.java +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/ClassValidationMvcIntegrationTest.java @@ -1,6 +1,5 @@ package com.baeldung.web.controller; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java index 384bd85ec6..bce5ab0a8c 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java @@ -20,7 +20,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.spring.web.config.WebConfig; import com.baeldung.spring.web.config.WebConfig; @RunWith(SpringJUnit4ClassRunner.class) From 8c34b3e93ba35f8d06cbda55d9e46f048997abe4 Mon Sep 17 00:00:00 2001 From: geroza Date: Wed, 9 Jan 2019 12:43:11 -0200 Subject: [PATCH 52/70] * removed temporary parent module parent-spring-5 --- parent-spring-5-1/README.md | 1 - parent-spring-5-1/pom.xml | 39 ------------------------------------- pom.xml | 6 ------ 3 files changed, 46 deletions(-) delete mode 100644 parent-spring-5-1/README.md delete mode 100644 parent-spring-5-1/pom.xml diff --git a/parent-spring-5-1/README.md b/parent-spring-5-1/README.md deleted file mode 100644 index ff12555376..0000000000 --- a/parent-spring-5-1/README.md +++ /dev/null @@ -1 +0,0 @@ -## Relevant articles: diff --git a/parent-spring-5-1/pom.xml b/parent-spring-5-1/pom.xml deleted file mode 100644 index 983e5e63eb..0000000000 --- a/parent-spring-5-1/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - 4.0.0 - com.baeldung - parent-spring-5-1 - 0.0.1-SNAPSHOT - pom - parent-spring-5-1 - Parent for all spring 5 core modules - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - org.springframework - spring-core - ${spring.version} - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - test - - - - - 5.0.6.RELEASE - 5.0.2 - 2.9.6 - 2.9.6 - 5.0.6.RELEASE - - - diff --git a/pom.xml b/pom.xml index 13b866b968..324f6129db 100644 --- a/pom.xml +++ b/pom.xml @@ -329,7 +329,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin @@ -601,7 +600,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin @@ -995,7 +993,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin @@ -1048,7 +1045,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin @@ -1316,7 +1312,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin @@ -1549,7 +1544,6 @@ parent-boot-2 parent-spring-4 parent-spring-5 - parent-spring-5-1 parent-java parent-kotlin From 94c146e245c78b2ddaf941f0f6e43fb1eff3a1b4 Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Thu, 10 Jan 2019 14:21:27 -0200 Subject: [PATCH 53/70] just to trigger the Travis build --- ethereum/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/README.md b/ethereum/README.md index 7accb4cd53..0c7ae3d4d2 100644 --- a/ethereum/README.md +++ b/ethereum/README.md @@ -4,4 +4,4 @@ - [Introduction to EthereumJ](http://www.baeldung.com/ethereumj) - [Creating and Deploying Smart Contracts with Solidity](http://www.baeldung.com/smart-contracts-ethereum-solidity) - [Lightweight Ethereum Clients Using Web3j](http://www.baeldung.com/web3j) - \ No newline at end of file + From 4fb05ab3a27bc4267db4d344a3987e875d55537d Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 10 Jan 2019 21:22:46 +0200 Subject: [PATCH 54/70] 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 55/70] 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 a15045f8a7f46a72268a088e4d0c7943cd17b456 Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Thu, 10 Jan 2019 18:17:59 -0200 Subject: [PATCH 56/70] edit readme to trigger travis build --- ethereum/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ethereum/README.md b/ethereum/README.md index 0c7ae3d4d2..d06ca09636 100644 --- a/ethereum/README.md +++ b/ethereum/README.md @@ -4,4 +4,3 @@ - [Introduction to EthereumJ](http://www.baeldung.com/ethereumj) - [Creating and Deploying Smart Contracts with Solidity](http://www.baeldung.com/smart-contracts-ethereum-solidity) - [Lightweight Ethereum Clients Using Web3j](http://www.baeldung.com/web3j) - From 7f501f169f7f7d22362e7e28cdb1331ad020ef55 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 10 Jan 2019 22:32:12 +0200 Subject: [PATCH 57/70] Update Circle.java --- core-java/src/main/java/com/baeldung/keyword/Circle.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java/src/main/java/com/baeldung/keyword/Circle.java b/core-java/src/main/java/com/baeldung/keyword/Circle.java index 4ec91d1b8a..231b2f5a59 100644 --- a/core-java/src/main/java/com/baeldung/keyword/Circle.java +++ b/core-java/src/main/java/com/baeldung/keyword/Circle.java @@ -1,4 +1,5 @@ package com.baeldung.keyword; public class Circle extends Round implements Shape { + } From b8dbc9d053a6f56eb2884baa7c811b713ce7a2ae Mon Sep 17 00:00:00 2001 From: Laurentiu Delcea Date: Thu, 10 Jan 2019 23:21:06 +0200 Subject: [PATCH 58/70] 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 59/70] 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 60/70] 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 61/70] 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 62/70] 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 63/70] 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 64/70] 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) From 2cb4faddb0edf2f05edb8d2cc77560e6205396fc Mon Sep 17 00:00:00 2001 From: Loredana Date: Fri, 11 Jan 2019 23:03:38 +0200 Subject: [PATCH 65/70] fix core-java test and back to build --- core-java/pom.xml | 1 + .../src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java | 2 ++ pom.xml | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core-java/pom.xml b/core-java/pom.xml index 6c58653d5a..d21c624997 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -13,6 +13,7 @@ ../parent-java + commons-io diff --git a/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java b/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java index 9fb3d03838..e710eecc66 100644 --- a/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java +++ b/core-java/src/test/java/com/baeldung/leapyear/LeapYearUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.leapyear; +import java.time.LocalDate; import java.time.Year; +import java.time.format.DateTimeFormatter; import java.util.GregorianCalendar; import org.junit.Assert; diff --git a/pom.xml b/pom.xml index a9b4b3f119..1c0738cafb 100644 --- a/pom.xml +++ b/pom.xml @@ -391,6 +391,7 @@ core-java-networking core-java-perf core-java-sun + core-java core-scala couchbase custom-pmd @@ -996,8 +997,7 @@ parent-spring-5 parent-java parent-kotlin - - core-java + core-java-concurrency-advanced core-kotlin From 469e36f07a93156664dd05dfb7efee58a7689c6b Mon Sep 17 00:00:00 2001 From: Juan Moreno Date: Sat, 12 Jan 2019 15:59:25 -0300 Subject: [PATCH 66/70] BAEL-2444 Extra examples (#6087) --- .../com/baeldung/time/InstantUnitTest.java | 42 +++++++++++++++++ .../time/InstantWithJMockUnitTest.java | 47 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 core-java-8/src/test/java/com/baeldung/time/InstantUnitTest.java create mode 100644 core-java-8/src/test/java/com/baeldung/time/InstantWithJMockUnitTest.java diff --git a/core-java-8/src/test/java/com/baeldung/time/InstantUnitTest.java b/core-java-8/src/test/java/com/baeldung/time/InstantUnitTest.java new file mode 100644 index 0000000000..8400748710 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/time/InstantUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.time; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ Instant.class }) +public class InstantUnitTest { + + @Test + public void givenInstantMock_whenNow_thenGetFixedInstant() { + String instantExpected = "2014-12-22T10:15:30Z"; + Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.of("UTC")); + Instant instant = Instant.now(clock); + mockStatic(Instant.class); + when(Instant.now()).thenReturn(instant); + + Instant now = Instant.now(); + + assertThat(now.toString()).isEqualTo(instantExpected); + } + + @Test + public void givenFixedClock_whenNow_thenGetFixedInstant() { + String instantExpected = "2014-12-22T10:15:30Z"; + Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.of("UTC")); + + Instant instant = Instant.now(clock); + + assertThat(instant.toString()).isEqualTo(instantExpected); + } +} diff --git a/core-java-8/src/test/java/com/baeldung/time/InstantWithJMockUnitTest.java b/core-java-8/src/test/java/com/baeldung/time/InstantWithJMockUnitTest.java new file mode 100644 index 0000000000..8f83b91101 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/time/InstantWithJMockUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.time; + +import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; +import org.junit.jupiter.api.Test; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +import static org.assertj.core.api.Assertions.assertThat; + +public class InstantWithJMockUnitTest { + + @Test + public void givenInstantWithJMock_whenNow_thenGetFixedInstant() { + String instantExpected = "2014-12-21T10:15:30Z"; + Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.of("UTC")); + new MockUp() { + @Mock + public Instant now() { + return Instant.now(clock); + } + }; + + Instant now = Instant.now(); + + assertThat(now.toString()).isEqualTo(instantExpected); + } + + @Test + public void givenInstantWithExpectations_whenNow_thenGetFixedInstant() { + Clock clock = Clock.fixed(Instant.parse("2014-12-23T10:15:30.00Z"), ZoneId.of("UTC")); + Instant instantExpected = Instant.now(clock); + new Expectations(Instant.class) { + { + Instant.now(); + result = instantExpected; + } + }; + + Instant now = Instant.now(); + + assertThat(now).isEqualTo(instantExpected); + } +} From b395dc1d418f5077ffe76c17d7d59fda9328c2ac Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Sat, 12 Jan 2019 18:57:19 -0200 Subject: [PATCH 67/70] Now using Auth and Resource servers from Baeldung/spring-security-oauth (#6128) --- .../OauthClientApplication.java | 4 +-- .../web/ClientRestController.java | 2 +- ....java => OauthClientLoginApplication.java} | 8 ++--- .../web/ClientRestController.java | 2 +- .../ClientCredentialsOauthApplication.java | 4 +-- .../service/WebClientChonJob.java | 6 ++-- .../ManualRequestApplication.java | 5 ++-- .../web/ManualOauthRequestController.java | 20 ++++++++----- ...nt-auth-code-client-application.properties | 8 ++--- ...ent-auth-code-login-application.properties | 12 ++++---- ...t-credentials-oauth-application.properties | 6 ++-- ...anual-request-oauth-application.properties | 3 ++ .../OAuth2ClientCredentialsLiveTest.java | 6 ++-- .../OAuth2ManualRequestLiveTest.java | 5 ++-- .../AuthorizationServerApplication.java | 17 ----------- .../configuration/WebSecurityConfig.java | 26 ----------------- .../ResourceServerApplication.java | 17 ----------- .../configuration/AuthorizationConfigs.java | 29 ------------------- .../web/ResourceRestController.java | 23 --------------- ...lient-authorization-application.properties | 13 --------- ...webclient-resources-application.properties | 6 ---- 21 files changed, 48 insertions(+), 174 deletions(-) rename spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/{OauthClientApplication.java => OauthClientLoginApplication.java} (62%) create mode 100644 spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties delete mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java delete mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java delete mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java delete mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java delete mode 100644 spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java delete mode 100644 spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties delete 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/webclient/authorizationcodeclient/OauthClientApplication.java b/spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodeclient/OauthClientApplication.java index 7bae78bb14..843d3f251f 100644 --- 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 @@ -6,9 +6,9 @@ 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 + * Note: This app is configured to use the authorization service and the resource service located in Baeldung/spring-security-oauth repo * - * 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 + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (john/123) and client configurations handled by the auth server * * @author rozagerardo * 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 index c36b7d1dea..9994a1255a 100644 --- 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 @@ -15,7 +15,7 @@ import reactor.core.publisher.Mono; @RestController public class ClientRestController { - private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + private static final String RESOURCE_URI = "http://localhost:8082/spring-security-oauth-resource/foos/1"; @Autowired WebClient webClient; 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/OauthClientLoginApplication.java similarity index 62% rename from spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientApplication.java rename to spring-5-reactive-oauth/src/main/java/com/baeldung/webclient/authorizationcodelogin/OauthClientLoginApplication.java index 9dd6dd1bde..e71e549ea4 100644 --- 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/OauthClientLoginApplication.java @@ -6,19 +6,19 @@ 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 + * Note: This app is configured to use the authorization service and the resource service located in Baeldung/spring-security-oauth repo * - * 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 + * As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (john/123) and client configurations handled by the auth server * * @author rozagerardo * */ @PropertySource("classpath:webclient-auth-code-login-application.properties") @SpringBootApplication -public class OauthClientApplication { +public class OauthClientLoginApplication { public static void main(String[] args) { - SpringApplication.run(OauthClientApplication.class, args); + SpringApplication.run(OauthClientLoginApplication.class, args); } } 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 index 55e0096525..24e5377f36 100644 --- 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 @@ -16,7 +16,7 @@ import reactor.core.publisher.Mono; @RestController public class ClientRestController { - private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + private static final String RESOURCE_URI = "http://localhost:8082/spring-security-oauth-resource/foos/1"; @Autowired WebClient webClient; 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 index d1b9f7f744..4356581819 100644 --- 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 @@ -7,9 +7,7 @@ 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) + * Note: This app is configured to use the authorization service and the resource service located in Baeldung/spring-security-oauth repo * * @author rozagerardo * 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 index dc38ce3f9e..ef39222933 100644 --- 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 @@ -4,8 +4,6 @@ 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; @@ -14,12 +12,12 @@ public class WebClientChonJob { Logger logger = LoggerFactory.getLogger(WebClientChonJob.class); - private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource"; + private static final String RESOURCE_URI = "localhost:8082/spring-security-oauth-resource/foos/1"; @Autowired private WebClient webClient; - @Scheduled(fixedRate = 1000) + @Scheduled(fixedRate = 5000) public void logResourceServiceResponse() { webClient.get() 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 index c2762ad559..59a63355f7 100644 --- 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 @@ -6,13 +6,12 @@ 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 + * Note: This app is configured to use the authorization service and the resource service located in Baeldung/spring-security-oauth repo * * @author rozagerardo * */ +@PropertySource("classpath:webclient-manual-request-oauth-application.properties") @SpringBootApplication public class ManualRequestApplication { 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 index 9f9d6d3167..d54d811032 100644 --- 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 @@ -3,8 +3,8 @@ package com.baeldung.webclient.manualrequest.web; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; 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; @@ -22,10 +22,16 @@ 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"; + private static final String RESOURCE_ENDPOINT = "localhost:8082/spring-security-oauth-resource/foos/1"; + + @Value("${the.authorization.client-id}") + private String clientId; + + @Value("${the.authorization.client-secret}") + private String clientSecret; + + @Value("${the.authorization.token-uri}") + private String tokenUri; @Autowired WebClient client; @@ -34,8 +40,8 @@ public class ManualOauthRequestController { 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())) + .uri(tokenUri) + .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((clientId + ":" + clientSecret).getBytes())) .body(BodyInserters.fromFormData(OAuth2ParameterNames.GRANT_TYPE, GrantType.CLIENT_CREDENTIALS.getValue())) .retrieve() .bodyToMono(JsonNode.class) 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 index 612777a06d..ac96aae6d6 100644 --- 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 @@ -1,10 +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.client-id=fooClientIdPassword +spring.security.oauth2.client.registration.bael.client-secret=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.oauth2.client.provider.bael.token-uri=http://localhost:8081/spring-security-oauth-server/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8081/spring-security-oauth-server/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 index edd5b80b13..e4dd0a532d 100644 --- 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 @@ -1,10 +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.client-id=fooClientIdPassword +spring.security.oauth2.client.registration.bael.client-secret=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 +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8081/spring-security-oauth-server/oauth/token +spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8081/spring-security-oauth-server/oauth/authorize +spring.security.oauth2.client.provider.bael.user-info-uri=http://localhost:8082/spring-security-oauth-resource/users/extra +spring.security.oauth2.client.provider.bael.user-name-attribute=user_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 index f82f74ec48..14c5b97605 100644 --- 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 @@ -1,4 +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 +spring.security.oauth2.client.registration.bael.client-id=fooClientIdPassword +spring.security.oauth2.client.registration.bael.client-secret=secret +spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8081/spring-security-oauth-server/oauth/token diff --git a/spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties b/spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties new file mode 100644 index 0000000000..36ec3defd1 --- /dev/null +++ b/spring-5-reactive-oauth/src/main/resources/webclient-manual-request-oauth-application.properties @@ -0,0 +1,3 @@ +the.authorization.client-id=fooClientIdPassword +the.authorization.client-secret=secret +the.authorization.token-uri=http://localhost:8081/spring-security-oauth-server/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 index e31815c3f8..ef913ba055 100644 --- 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 @@ -19,9 +19,9 @@ 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 + * Note: this Live test requires the Authorization Service and the Resource service located in the Baeldung/spring-security-oauth repo * - * @author ger + * @author rozagerardo * */ @RunWith(SpringRunner.class) @@ -46,7 +46,7 @@ public class OAuth2ClientCredentialsLiveTest { .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!")); + assertThat(allLoggedEntries).anyMatch(entry -> entry.contains("We retrieved the following resource using Client Credentials Grant Type: {\"id\"")); } } 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 index 94aa580f0a..2381264926 100644 --- 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 @@ -1,5 +1,6 @@ package com.baeldung.webclient.manualrequest; +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.springframework.test.web.reactive.server.WebTestClient; @@ -8,7 +9,7 @@ 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. + * but also the Authorization Service and the Resource service located in the Baeldung/spring-security-oauth repo * * * @author ger @@ -37,7 +38,7 @@ public class OAuth2ManualRequestLiveTest { response.expectStatus() .isOk() .expectBody(String.class) - .isEqualTo("Retrieved the resource using a manual approach: This is the resource!"); + .value(Matchers.containsString("Retrieved the resource using a manual approach: {\"id\"")); } } 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 deleted file mode 100644 index d72704386c..0000000000 --- a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/AuthorizationServerApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 5dd15f1b8c..0000000000 --- a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/authorizationserver/configuration/WebSecurityConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index 50ad293ef8..0000000000 --- a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/ResourceServerApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 5aea1983db..0000000000 --- a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/configuration/AuthorizationConfigs.java +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index aef0fb4d7d..0000000000 --- a/spring-5-security-oauth/src/main/java/com/baeldung/webclient/resourceserver/web/ResourceRestController.java +++ /dev/null @@ -1,23 +0,0 @@ -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/webclient-authorization-application.properties b/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties deleted file mode 100644 index 9531045359..0000000000 --- a/spring-5-security-oauth/src/main/resources/webclient-authorization-application.properties +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 1cfb9ca12d..0000000000 --- a/spring-5-security-oauth/src/main/resources/webclient-resources-application.properties +++ /dev/null @@ -1,6 +0,0 @@ -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 dcc1cd3850cdb3dbbfa6df343604ac4b720cd424 Mon Sep 17 00:00:00 2001 From: chandra Date: Sat, 12 Jan 2019 16:52:52 -0500 Subject: [PATCH 68/70] BAEL-2088 Common Hibernate Exceptions Commin Hibernate Exceptions unit tests --- .../hibernate/exception/EntityWithNoId.java | 16 + .../hibernate/exception/HibernateUtil.java | 63 +++ .../baeldung/hibernate/exception/Product.java | 40 ++ .../exception/HibernateExceptionUnitTest.java | 425 ++++++++++++++++++ .../resources/hibernate-exception.properties | 16 + 5 files changed, 560 insertions(+) create mode 100644 persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java create mode 100644 persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java create mode 100644 persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/Product.java create mode 100644 persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java create mode 100644 persistence-modules/hibernate5/src/test/resources/hibernate-exception.properties diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java new file mode 100644 index 0000000000..989fa1281a --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java @@ -0,0 +1,16 @@ +package com.baeldung.hibernate.exception; + +import javax.persistence.Entity; + +@Entity +public class EntityWithNoId { + private int id; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java new file mode 100644 index 0000000000..ae5174ac9c --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java @@ -0,0 +1,63 @@ +package com.baeldung.hibernate.exception; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.ServiceRegistry; + +public class HibernateUtil { + private static SessionFactory sessionFactory; + private static String PROPERTY_FILE_NAME; + + public static SessionFactory getSessionFactory() throws IOException { + return getSessionFactory(null); + } + + public static SessionFactory getSessionFactory(String propertyFileName) + throws IOException { + PROPERTY_FILE_NAME = propertyFileName; + if (sessionFactory == null) { + ServiceRegistry serviceRegistry = configureServiceRegistry(); + sessionFactory = makeSessionFactory(serviceRegistry); + } + return sessionFactory; + } + + private static SessionFactory makeSessionFactory( + ServiceRegistry serviceRegistry) { + MetadataSources metadataSources = new MetadataSources(serviceRegistry); + metadataSources.addAnnotatedClass(Product.class); + Metadata metadata = metadataSources.getMetadataBuilder() + .build(); + return metadata.getSessionFactoryBuilder() + .build(); + + } + + private static ServiceRegistry configureServiceRegistry() + throws IOException { + Properties properties = getProperties(); + return new StandardServiceRegistryBuilder().applySettings(properties) + .build(); + } + + private static Properties getProperties() throws IOException { + Properties properties = new Properties(); + URL propertiesURL = Thread.currentThread() + .getContextClassLoader() + .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, + "hibernate-exception.properties")); + try (FileInputStream inputStream = new FileInputStream( + propertiesURL.getFile())) { + properties.load(inputStream); + } + return properties; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/Product.java b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/Product.java new file mode 100644 index 0000000000..031fa38de0 --- /dev/null +++ b/persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/exception/Product.java @@ -0,0 +1,40 @@ +package com.baeldung.hibernate.exception; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Product { + + private int id; + + private String name; + private String description; + + @Id + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @Column(nullable=false) + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java new file mode 100644 index 0000000000..3581c81daa --- /dev/null +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java @@ -0,0 +1,425 @@ +package com.baeldung.hibernate.exception; + +import static org.hamcrest.CoreMatchers.isA; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.util.List; + +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; + +import org.hibernate.AnnotationException; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.NonUniqueObjectException; +import org.hibernate.PropertyValueException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.StaleObjectStateException; +import org.hibernate.StaleStateException; +import org.hibernate.Transaction; +import org.hibernate.TransactionException; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.DataException; +import org.hibernate.exception.SQLGrammarException; +import org.hibernate.query.NativeQuery; +import org.hibernate.tool.schema.spi.CommandAcceptanceException; +import org.hibernate.tool.schema.spi.SchemaManagementException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HibernateExceptionUnitTest { + + private static final Logger logger = LoggerFactory + .getLogger(HibernateExceptionUnitTest.class); + private SessionFactory sessionFactory; + + @Before + public void setUp() throws IOException { + sessionFactory = HibernateUtil.getSessionFactory(); + } + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private Configuration getConfiguration() { + Configuration cfg = new Configuration(); + cfg.setProperty(AvailableSettings.DIALECT, + "org.hibernate.dialect.H2Dialect"); + cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "none"); + cfg.setProperty(AvailableSettings.DRIVER, "org.h2.Driver"); + cfg.setProperty(AvailableSettings.URL, + "jdbc:h2:mem:myexceptiondb2;DB_CLOSE_DELAY=-1"); + cfg.setProperty(AvailableSettings.USER, "sa"); + cfg.setProperty(AvailableSettings.PASS, ""); + return cfg; + } + + @Test + public void whenQueryExecutedWithUnmappedEntity_thenMappingException() { + thrown.expectCause(isA(MappingException.class)); + thrown.expectMessage("Unknown entity: java.lang.String"); + + Session session = sessionFactory.openSession(); + NativeQuery query = session + .createNativeQuery("select name from PRODUCT", String.class); + query.getResultList(); + } + + @Test + @SuppressWarnings("rawtypes") + public void whenQueryExecuted_thenOK() { + Session session = sessionFactory.openSession(); + NativeQuery query = session + .createNativeQuery("select name from PRODUCT"); + List results = query.getResultList(); + assertNotNull(results); + } + + @Test + public void givenEntityWithoutId_whenSessionFactoryCreated_thenAnnotationException() { + thrown.expect(AnnotationException.class); + thrown.expectMessage("No identifier specified for entity"); + + Configuration cfg = getConfiguration(); + cfg.addAnnotatedClass(EntityWithNoId.class); + cfg.buildSessionFactory(); + } + + @Test + public void givenMissingTable_whenSchemaValidated_thenSchemaManagementException() { + thrown.expect(SchemaManagementException.class); + thrown.expectMessage("Schema-validation: missing table"); + + Configuration cfg = getConfiguration(); + cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "validate"); + cfg.addAnnotatedClass(Product.class); + cfg.buildSessionFactory(); + } + + @Test + public void whenWrongDialectSpecified_thenCommandAcceptanceException() { + thrown.expect(SchemaManagementException.class); + thrown.expectCause(isA(CommandAcceptanceException.class)); + thrown.expectMessage("Halting on error : Error executing DDL"); + + Configuration cfg = getConfiguration(); + cfg.setProperty(AvailableSettings.DIALECT, + "org.hibernate.dialect.MySQLDialect"); + cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "update"); + + // This does not work due to hibernate bug + // cfg.setProperty(AvailableSettings.HBM2DDL_HALT_ON_ERROR,"true"); + cfg.getProperties() + .put(AvailableSettings.HBM2DDL_HALT_ON_ERROR, true); + + cfg.addAnnotatedClass(Product.class); + cfg.buildSessionFactory(); + } + + @Test + public void givenMissingTable_whenEntitySaved_thenSQLGrammarException() { + thrown.expect(isA(PersistenceException.class)); + thrown.expectCause(isA(SQLGrammarException.class)); + thrown + .expectMessage("SQLGrammarException: could not prepare statement"); + + Configuration cfg = getConfiguration(); + cfg.addAnnotatedClass(Product.class); + + SessionFactory sessionFactory = cfg.buildSessionFactory(); + Session session = null; + Transaction transaction = null; + try { + + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + Product product = new Product(); + product.setId(1); + product.setName("Product 1"); + session.save(product); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + closeSessionFactoryQuietly(sessionFactory); + } + } + + @Test + public void givenMissingTable_whenQueryExecuted_thenSQLGrammarException() { + thrown.expect(isA(PersistenceException.class)); + thrown.expectCause(isA(SQLGrammarException.class)); + thrown + .expectMessage("SQLGrammarException: could not prepare statement"); + + Session session = sessionFactory.openSession(); + NativeQuery query = session.createNativeQuery( + "select * from NON_EXISTING_TABLE", Product.class); + query.getResultList(); + } + + @Test + public void whenDuplicateIdSaved_thenConstraintViolationException() { + thrown.expect(isA(PersistenceException.class)); + thrown.expectCause(isA(ConstraintViolationException.class)); + thrown.expectMessage( + "ConstraintViolationException: could not execute statement"); + + Session session = null; + Transaction transaction = null; + + for (int i = 1; i <= 2; i++) { + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + Product product = new Product(); + product.setId(1); + product.setName("Product " + i); + session.save(product); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } + } + + @Test + public void givenNotNullPropertyNotSet_whenEntityIdSaved_thenPropertyValueException() { + thrown.expect(isA(PropertyValueException.class)); + thrown.expectMessage( + "not-null property references a null or transient value"); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product = new Product(); + product.setId(1); + session.save(product); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + + } + + @Test + public void givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException() { + thrown.expectCause(isA(DataException.class)); + thrown.expectMessage( + "org.hibernate.exception.DataException: could not prepare statement"); + + Session session = sessionFactory.openSession(); + NativeQuery query = session.createNativeQuery( + "select * from PRODUCT where id='wrongTypeId'", Product.class); + query.getResultList(); + } + + @Test + public void givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException() { + thrown.expect(isA(NonUniqueObjectException.class)); + thrown.expectMessage( + "A different object with the same identifier value was already associated with the session"); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product1 = new Product(); + product1.setId(1); + product1.setName("Product 1"); + session.save(product1); + + Product product2 = new Product(); + product2.setId(1); + product2.setName("Product 2"); + session.save(product2); + + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } + + @Test + public void whenDeletingADeletedObject_thenOptimisticLockException() { + thrown.expect(isA(OptimisticLockException.class)); + thrown.expectMessage( + "Batch update returned unexpected row count from update"); + thrown.expectCause(isA(StaleStateException.class)); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product1 = new Product(); + product1.setId(12); + product1.setName("Product 12"); + session.save(product1); + transaction.commit(); + session.close(); + + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + Product product2 = session.get(Product.class, 12); + session.createNativeQuery("delete from Product where id=12") + .executeUpdate(); + // We need to refresh to fix the error. + // session.refresh(product2); + session.delete(product2); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } + + @Test + public void whenUpdatingNonExistingObject_thenStaleStateException() { + thrown.expect(isA(OptimisticLockException.class)); + thrown + .expectMessage("Row was updated or deleted by another transaction"); + thrown.expectCause(isA(StaleObjectStateException.class)); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product1 = new Product(); + product1.setId(15); + product1.setName("Product1"); + session.update(product1); + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } + + @Test + public void givenTxnMarkedRollbackOnly_whenCommitted_thenTransactionException() { + thrown.expect(isA(TransactionException.class)); + + Session session = null; + Transaction transaction = null; + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product1 = new Product(); + product1.setId(15); + product1.setName("Product1"); + session.save(product1); + transaction.setRollbackOnly(); + + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } + + private void rollbackTransactionQuietly(Transaction transaction) { + if (transaction != null && transaction.isActive()) { + try { + transaction.rollback(); + } catch (Exception e) { + logger.error("Exception while rolling back transaction", e); + } + } + } + + private void closeSessionQuietly(Session session) { + if (session != null) { + try { + session.close(); + } catch (Exception e) { + logger.error("Exception while closing session", e); + } + } + } + + private void closeSessionFactoryQuietly(SessionFactory sessionFactory) { + if (sessionFactory != null) { + try { + sessionFactory.close(); + } catch (Exception e) { + logger.error("Exception while closing sessionFactory", e); + } + } + } + + @Test + public void givenExistingEntity_whenIdUpdated_thenHibernateException() { + thrown.expect(isA(PersistenceException.class)); + thrown.expectCause(isA(HibernateException.class)); + thrown.expectMessage( + "identifier of an instance of com.baeldung.hibernate.exception.Product was altered"); + + Session session = null; + Transaction transaction = null; + + try { + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product1 = new Product(); + product1.setId(222); + product1.setName("Product 222"); + session.save(product1); + transaction.commit(); + closeSessionQuietly(session); + + session = sessionFactory.openSession(); + transaction = session.beginTransaction(); + + Product product2 = session.get(Product.class, 222); + product2.setId(333); + session.save(product2); + + transaction.commit(); + } catch (Exception e) { + rollbackTransactionQuietly(transaction); + throw (e); + } finally { + closeSessionQuietly(session); + } + } +} diff --git a/persistence-modules/hibernate5/src/test/resources/hibernate-exception.properties b/persistence-modules/hibernate5/src/test/resources/hibernate-exception.properties new file mode 100644 index 0000000000..e08a23166d --- /dev/null +++ b/persistence-modules/hibernate5/src/test/resources/hibernate-exception.properties @@ -0,0 +1,16 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:myexceptiondb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop + +hibernate.c3p0.min_size=5 +hibernate.c3p0.max_size=20 +hibernate.c3p0.acquire_increment=5 +hibernate.c3p0.timeout=1800 + +hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory From 4f103eeb278324ad943e8b5ad17542fc04902ea5 Mon Sep 17 00:00:00 2001 From: Loredana Date: Sun, 13 Jan 2019 10:32:02 +0200 Subject: [PATCH 69/70] move instanceof code --- .../src/main/java/com/baeldung/keyword/Circle.java | 0 .../src/main/java/com/baeldung/keyword/Ring.java | 0 .../src/main/java/com/baeldung/keyword/Round.java | 0 .../src/main/java/com/baeldung/keyword/Shape.java | 0 .../src/main/java/com/baeldung/keyword/Triangle.java | 0 .../test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {core-java => core-java-lang-syntax}/src/main/java/com/baeldung/keyword/Circle.java (100%) rename {core-java => core-java-lang-syntax}/src/main/java/com/baeldung/keyword/Ring.java (100%) rename {core-java => core-java-lang-syntax}/src/main/java/com/baeldung/keyword/Round.java (100%) rename {core-java => core-java-lang-syntax}/src/main/java/com/baeldung/keyword/Shape.java (100%) rename {core-java => core-java-lang-syntax}/src/main/java/com/baeldung/keyword/Triangle.java (100%) rename {core-java => core-java-lang-syntax}/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java (100%) diff --git a/core-java/src/main/java/com/baeldung/keyword/Circle.java b/core-java-lang-syntax/src/main/java/com/baeldung/keyword/Circle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keyword/Circle.java rename to core-java-lang-syntax/src/main/java/com/baeldung/keyword/Circle.java diff --git a/core-java/src/main/java/com/baeldung/keyword/Ring.java b/core-java-lang-syntax/src/main/java/com/baeldung/keyword/Ring.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keyword/Ring.java rename to core-java-lang-syntax/src/main/java/com/baeldung/keyword/Ring.java diff --git a/core-java/src/main/java/com/baeldung/keyword/Round.java b/core-java-lang-syntax/src/main/java/com/baeldung/keyword/Round.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keyword/Round.java rename to core-java-lang-syntax/src/main/java/com/baeldung/keyword/Round.java diff --git a/core-java/src/main/java/com/baeldung/keyword/Shape.java b/core-java-lang-syntax/src/main/java/com/baeldung/keyword/Shape.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keyword/Shape.java rename to core-java-lang-syntax/src/main/java/com/baeldung/keyword/Shape.java diff --git a/core-java/src/main/java/com/baeldung/keyword/Triangle.java b/core-java-lang-syntax/src/main/java/com/baeldung/keyword/Triangle.java similarity index 100% rename from core-java/src/main/java/com/baeldung/keyword/Triangle.java rename to core-java-lang-syntax/src/main/java/com/baeldung/keyword/Triangle.java diff --git a/core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java b/core-java-lang-syntax/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java similarity index 100% rename from core-java/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java rename to core-java-lang-syntax/src/test/java/com/baeldung/keyword/test/InstanceOfUnitTest.java From e7412182a9e7f8d5e5ab13760b23580aad940d24 Mon Sep 17 00:00:00 2001 From: fanatixan Date: Sun, 13 Jan 2019 22:27:07 +0100 Subject: [PATCH 70/70] bael-2508 - Stream.peek() examples (#6132) * bael-2508 - Stream.peek() examples * beal-2508 additional example * bael-2508 moving examples --- .../com/baeldung/stream/PeekUnitTest.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 java-streams/src/test/java/com/baeldung/stream/PeekUnitTest.java diff --git a/java-streams/src/test/java/com/baeldung/stream/PeekUnitTest.java b/java-streams/src/test/java/com/baeldung/stream/PeekUnitTest.java new file mode 100644 index 0000000000..a3a2816e9c --- /dev/null +++ b/java-streams/src/test/java/com/baeldung/stream/PeekUnitTest.java @@ -0,0 +1,118 @@ +package com.baeldung.stream; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.StringWriter; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class PeekUnitTest { + + private StringWriter out; + + @BeforeEach + void setup() { + out = new StringWriter(); + } + + @Test + void givenStringStream_whenCallingPeekOnly_thenNoElementProcessed() { + // given + Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); + + // when + nameStream.peek(out::append); + + // then + assertThat(out.toString()).isEmpty(); + } + + @Test + void givenStringStream_whenCallingForEachOnly_thenElementsProcessed() { + // given + Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); + + // when + nameStream.forEach(out::append); + + // then + assertThat(out.toString()).isEqualTo("AliceBobChuck"); + } + + @Test + void givenStringStream_whenCallingPeekAndNoopForEach_thenElementsProcessed() { + // given + Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); + + // when + nameStream.peek(out::append) + .forEach(this::noop); + + // then + assertThat(out.toString()).isEqualTo("AliceBobChuck"); + } + + @Test + void givenStringStream_whenCallingPeekAndCollect_thenElementsProcessed() { + // given + Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); + + // when + nameStream.peek(out::append) + .collect(Collectors.toList()); + + // then + assertThat(out.toString()).isEqualTo("AliceBobChuck"); + } + + @Test + void givenStringStream_whenCallingPeekAndForEach_thenElementsProcessedTwice() { + // given + Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); + + // when + nameStream.peek(out::append) + .forEach(out::append); + + // then + assertThat(out.toString()).isEqualTo("AliceAliceBobBobChuckChuck"); + } + + @Test + void givenStringStream_whenCallingPeek_thenElementsProcessedTwice() { + // given + Stream userStream = Stream.of(new User("Alice"), new User("Bob"), new User("Chuck")); + + // when + userStream.peek(u -> u.setName(u.getName().toLowerCase())) + .map(User::getName) + .forEach(out::append); + + // then + assertThat(out.toString()).isEqualTo("alicebobchuck"); + } + + private static class User { + private String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } + + private void noop(String s) { + } + +}