diff --git a/core-java/README.md b/core-java/README.md index 59aab91aa9..627535d1e5 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -158,3 +158,4 @@ - [Java Switch Statement](https://www.baeldung.com/java-switch) - [The Modulo Operator in Java](https://www.baeldung.com/modulo-java) - [Ternary Operator In Java](https://www.baeldung.com/java-ternary-operator) +- [Merging java.util.Properties Objects](https://www.baeldung.com/java-merging-properties) diff --git a/gson/README.md b/gson/README.md index 4122b21431..e1eb155f43 100644 --- a/gson/README.md +++ b/gson/README.md @@ -8,3 +8,4 @@ - [Jackson vs Gson](http://www.baeldung.com/jackson-vs-gson) - [Exclude Fields from Serialization in Gson](http://www.baeldung.com/gson-exclude-fields-serialization) - [Save Data to a JSON File with Gson](https://www.baeldung.com/gson-save-file) +- [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map) diff --git a/gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java b/gson/src/main/java/org/baeldung/gson/serialization/MapDeserializer.java similarity index 62% rename from gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java rename to gson/src/main/java/org/baeldung/gson/serialization/MapDeserializer.java index bb73e32559..cdeb2e23c8 100644 --- a/gson/src/main/java/org/baeldung/gson/serialization/HashMapDeserializer.java +++ b/gson/src/main/java/org/baeldung/gson/serialization/MapDeserializer.java @@ -4,28 +4,26 @@ import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; import org.baeldung.gson.entities.Employee; import com.google.gson.*; -public class HashMapDeserializer implements JsonDeserializer> { +public class MapDeserializer implements JsonDeserializer> { @Override - public HashMap deserialize(JsonElement elem, Type type, JsonDeserializationContext context) throws JsonParseException { - HashMap map = new HashMap<>(); - for (Map.Entry entry : elem.getAsJsonObject().entrySet()) { - JsonElement jsonValue = entry.getValue(); - Object value = null; - if (jsonValue.isJsonPrimitive()) { - value = toPrimitive(jsonValue.getAsJsonPrimitive(), context); - } else { - value = context.deserialize(jsonValue, Employee.class); - } - map.put(entry.getKey(), value); - } - return map; + public Map deserialize(JsonElement elem, Type type, JsonDeserializationContext context) throws JsonParseException { + return elem.getAsJsonObject() + .entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> e.getValue().isJsonPrimitive() ? + toPrimitive(e.getValue().getAsJsonPrimitive(), context) + : context.deserialize(e.getValue(), Employee.class) + )); } private Object toPrimitive(JsonPrimitive jsonValue, JsonDeserializationContext context) { diff --git a/gson/src/main/java/org/baeldung/gson/serialization/StringDateMapDeserializer.java b/gson/src/main/java/org/baeldung/gson/serialization/StringDateMapDeserializer.java new file mode 100644 index 0000000000..f18bdbc84f --- /dev/null +++ b/gson/src/main/java/org/baeldung/gson/serialization/StringDateMapDeserializer.java @@ -0,0 +1,44 @@ +package org.baeldung.gson.serialization; + +import java.lang.reflect.Type; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +public class StringDateMapDeserializer implements JsonDeserializer> { + + private static final Logger logger = LoggerFactory.getLogger(StringDateMapDeserializer.class); + + private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); + + @Override + public Map deserialize(JsonElement elem, Type type, JsonDeserializationContext jsonDeserializationContext) { + System.out.println("Deserializer called"); + logger.info("Deserializer called"); + return elem.getAsJsonObject() + .entrySet() + .stream() + .filter(e -> e.getValue().isJsonPrimitive()) + .filter(e -> e.getValue().getAsJsonPrimitive().isString()) + .collect(Collectors.toMap(Map.Entry::getKey, e -> formatDate(e.getValue()))); + } + + private Date formatDate(JsonElement value) { + try { + return format.parse(value.getAsString()); + } catch (ParseException ex) { + throw new JsonParseException(ex); + } + } + +} diff --git a/gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java b/gson/src/test/java/org/baeldung/gson/deserialization/MapDeserializationUnitTest.java similarity index 58% rename from gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java rename to gson/src/test/java/org/baeldung/gson/deserialization/MapDeserializationUnitTest.java index 6905ade0da..a5ae4194e8 100644 --- a/gson/src/test/java/org/baeldung/gson/deserialization/HashMapDeserializationUnitTest.java +++ b/gson/src/test/java/org/baeldung/gson/deserialization/MapDeserializationUnitTest.java @@ -1,10 +1,14 @@ package org.baeldung.gson.deserialization; import java.lang.reflect.Type; -import java.util.HashMap; +import java.text.ParseException; +import java.util.Date; +import java.util.Map; +import org.apache.commons.lang3.time.DateUtils; import org.baeldung.gson.entities.Employee; -import org.baeldung.gson.serialization.HashMapDeserializer; +import org.baeldung.gson.serialization.MapDeserializer; +import org.baeldung.gson.serialization.StringDateMapDeserializer; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -16,18 +20,18 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.internal.LinkedTreeMap; import com.google.gson.reflect.TypeToken; -public class HashMapDeserializationUnitTest { +public class MapDeserializationUnitTest { - private static final Logger logger = LoggerFactory.getLogger(HashMapDeserializationUnitTest.class); + private static final Logger logger = LoggerFactory.getLogger(MapDeserializationUnitTest.class); @Test - public void whenUsingHashMapClass_thenShouldReturnMapWithDefaultClasses() { + public void whenUsingMapClass_thenShouldReturnMapWithDefaultClasses() { String jsonString = "{'employee.name':'Bob','employee.salary':10000, 'employee.active':true, " + "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}"; Gson gson = new Gson(); - HashMap map = gson.fromJson(jsonString, HashMap.class); + Map map = gson.fromJson(jsonString, Map.class); logger.info("The converted map: {}", map); Assert.assertEquals(4, map.size()); @@ -43,7 +47,7 @@ public class HashMapDeserializationUnitTest { + "'employee.active':true, " + "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}"; Gson gson = new Gson(); - HashMap map = gson.fromJson(jsonString, HashMap.class); + Map map = gson.fromJson(jsonString, Map.class); logger.info("The converted map: {}", map); } @@ -56,8 +60,8 @@ public class HashMapDeserializationUnitTest { + "'Steve':{'id':10, 'name': 'Steven Waugh', 'address':'Australia'}}"; Gson gson = new Gson(); - Type empMapType = new TypeToken>(){}.getType(); - HashMap nameEmployeeMap = gson.fromJson(jsonString, empMapType); + Type empMapType = new TypeToken>(){}.getType(); + Map nameEmployeeMap = gson.fromJson(jsonString, empMapType); logger.info("The converted map: {}", nameEmployeeMap); Assert.assertEquals(3, nameEmployeeMap.size()); @@ -70,11 +74,11 @@ public class HashMapDeserializationUnitTest { String jsonString = "{'employee.name':'Bob','employee.salary':10000, 'employee.active':true, " + "'employee':{'id':10, 'name': 'Bob Willis', 'address':'London'}}"; - Type type = new TypeToken>(){}.getType(); + Type type = new TypeToken>(){}.getType(); Gson gson = new GsonBuilder() - .registerTypeAdapter(type, new HashMapDeserializer()) + .registerTypeAdapter(type, new MapDeserializer()) .create(); - HashMap blendedMap = gson.fromJson(jsonString, type); + Map blendedMap = gson.fromJson(jsonString, type); logger.info("The converted map: {}", blendedMap); Assert.assertEquals(4, blendedMap.size()); @@ -83,4 +87,26 @@ public class HashMapDeserializationUnitTest { } + @Test + public void whenUsingCustomDateDeserializer_thenShouldReturnMapWithDate() { + String jsonString = "{'Bob': '2017/06/01', 'Jennie':'2015/01/03'}"; + Type type = new TypeToken>(){}.getType(); + Gson gson = new GsonBuilder() + .registerTypeAdapter(type, new StringDateMapDeserializer()) + .create(); + Map empJoiningDateMap = gson.fromJson(jsonString, type); + + logger.info("The converted map: {}", empJoiningDateMap); + logger.info("The map class {}", empJoiningDateMap.getClass()); + Assert.assertEquals(2, empJoiningDateMap.size()); + Assert.assertEquals(Date.class, empJoiningDateMap.get("Bob").getClass()); + Date dt = null; + try { + dt = DateUtils.parseDate("2017-06-01", "yyyy-MM-dd"); + Assert.assertEquals(dt, empJoiningDateMap.get("Bob")); + } catch (ParseException e) { + logger.error("Could not parse date", e); + } + } + } diff --git a/helidon/README.md b/helidon/README.md new file mode 100644 index 0000000000..a092faf9f2 --- /dev/null +++ b/helidon/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Microservices with Oracle Helidon](https://www.baeldung.com/microservices-oracle-helidon) diff --git a/lombok/README.md b/lombok/README.md index a297aeb31e..34ec569e89 100644 --- a/lombok/README.md +++ b/lombok/README.md @@ -4,3 +4,4 @@ - [Using Lombok’s @Getter for Boolean Fields](https://www.baeldung.com/lombok-getter-boolean) - [Lombok @Builder with Inheritance](https://www.baeldung.com/lombok-builder-inheritance) - [Lombok Builder with Default Value](https://www.baeldung.com/lombok-builder-default-value) +- [Lombok Builder with Custom Setter](https://www.baeldung.com/lombok-builder-with-custom-setter) diff --git a/lombok/src/main/java/com/baeldung/lombok/builder/customsetter/Message.java b/lombok/src/main/java/com/baeldung/lombok/builder/customsetter/Message.java new file mode 100644 index 0000000000..6c58763143 --- /dev/null +++ b/lombok/src/main/java/com/baeldung/lombok/builder/customsetter/Message.java @@ -0,0 +1,39 @@ +package com.baeldung.lombok.builder.customsetter; + +import java.io.File; +import java.util.List; + +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +public class Message { + private String sender; + private String recipient; + private String text; + private File file; + + public static class MessageBuilder { + private String text; + private File file; + + public MessageBuilder text(String text) { + this.text = text; + verifyTextOrFile(); + return this; + } + + public MessageBuilder file(File file) { + this.file = file; + verifyTextOrFile(); + return this; + } + + private void verifyTextOrFile() { + if (text != null && file != null) { + throw new IllegalStateException("Cannot send 'text' and 'file'."); + } + } + } +} diff --git a/lombok/src/test/java/com/baeldung/lombok/builder/customsetter/BuilderWithCustomSetterUnitTest.java b/lombok/src/test/java/com/baeldung/lombok/builder/customsetter/BuilderWithCustomSetterUnitTest.java new file mode 100644 index 0000000000..3143747f0d --- /dev/null +++ b/lombok/src/test/java/com/baeldung/lombok/builder/customsetter/BuilderWithCustomSetterUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.lombok.builder.customsetter; + +import java.io.File; + +import org.junit.Test; + +public class BuilderWithCustomSetterUnitTest { + + @Test + public void givenBuilderWithCustomSetter_TestTextOnly() { + Message message = Message.builder() + .sender("user@somedomain.com") + .recipient("someuser@otherdomain.com") + .text("How are you today?") + .build(); + } + + @Test + public void givenBuilderWithCustomSetter_TestFileOnly() { + Message message = Message.builder() + .sender("user@somedomain.com") + .recipient("someuser@otherdomain.com") + .file(new File("/path/to/file")) + .build(); + } + + @Test(expected = IllegalStateException.class) + public void givenBuilderWithCustomSetter_TestTextAndFile() { + Message message = Message.builder() + .sender("user@somedomain.com") + .recipient("someuser@otherdomain.com") + .text("How are you today?") + .file(new File("/path/to/file")) + .build(); + } + +} diff --git a/parent-boot-1/pom.xml b/parent-boot-1/pom.xml index c61b791ef3..171806390d 100644 --- a/parent-boot-1/pom.xml +++ b/parent-boot-1/pom.xml @@ -43,6 +43,10 @@ org.springframework.boot spring-boot-maven-plugin ${spring-boot.version} + + ${start-class} + + diff --git a/persistence-modules/spring-data-dynamodb/pom.xml b/persistence-modules/spring-data-dynamodb/pom.xml index 4cb805131a..e8bf9b8c1e 100644 --- a/persistence-modules/spring-data-dynamodb/pom.xml +++ b/persistence-modules/spring-data-dynamodb/pom.xml @@ -1,9 +1,7 @@ 4.0.0 - com.baeldung spring-data-dynamodb - 0.0.1-SNAPSHOT jar spring-data-dynamodb This is simple boot application for Spring boot dynamodb test @@ -85,7 +83,6 @@ org.apache.httpcomponents httpclient - ${httpclient.version} diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index b9b97eb076..368f3ada14 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -1,9 +1,7 @@ 4.0.0 - com.baeldung spring-aop - 0.0.1-SNAPSHOT war spring-aop diff --git a/spring-boot-crud/README.md b/spring-boot-crud/README.md new file mode 100644 index 0000000000..566cb327a8 --- /dev/null +++ b/spring-boot-crud/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Spring Boot CRUD Application with Thymeleaf](https://www.baeldung.com/spring-boot-crud-thymeleaf) diff --git a/spring-cloud/spring-cloud-aws/pom.xml b/spring-cloud/spring-cloud-aws/pom.xml index 6933845173..09518483a4 100644 --- a/spring-cloud/spring-cloud-aws/pom.xml +++ b/spring-cloud/spring-cloud-aws/pom.xml @@ -49,8 +49,8 @@ org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} + spring-cloud-aws + 2.0.1.RELEASE pom import diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/Odd.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/Odd.java new file mode 100644 index 0000000000..f60f1764c6 --- /dev/null +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/Odd.java @@ -0,0 +1,49 @@ +package com.baeldung.restassured; + +public class Odd { + + float price; + int status; + float ck; + String name; + + Odd(float price, int status, float ck, String name) { + this.price = price; + this.status = status; + this.ck = ck; + this.name = name; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public float getCk() { + return ck; + } + + public void setCk(float ck) { + this.ck = ck; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/RestAssured2IntegrationTest.java b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/RestAssured2IntegrationTest.java index 1b691414db..805d67271d 100644 --- a/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/RestAssured2IntegrationTest.java +++ b/testing-modules/rest-assured/src/test/java/com/baeldung/restassured/RestAssured2IntegrationTest.java @@ -5,13 +5,15 @@ import io.restassured.RestAssured; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.with; import static org.hamcrest.Matchers.hasItems; public class RestAssured2IntegrationTest { @@ -32,6 +34,9 @@ public class RestAssured2IntegrationTest { aResponse().withStatus(200) .withHeader("Content-Type", APPLICATION_JSON) .withBody(ODDS))); + stubFor(post(urlEqualTo("/odds/new")) + .withRequestBody(containing("{\"price\":5.25,\"status\":1,\"ck\":13.1,\"name\":\"X\"}")) + .willReturn(aResponse().withStatus(201))); } @Test @@ -40,6 +45,15 @@ public class RestAssured2IntegrationTest { hasItems(5.25f, 1.2f)); } + @Test + public void whenRequestedPost_thenCreated() { + with().body(new Odd(5.25f, 1, 13.1f, "X")) + .when() + .request("POST", "/odds/new") + .then() + .statusCode(201); + } + private static String getJson() { return Util.inputStreamToString(RestAssured2IntegrationTest.class .getResourceAsStream("/odds.json"));