diff --git a/lombok-intro/pom.xml b/lombok-intro/pom.xml
new file mode 100644
index 0000000000..8204a0ee70
--- /dev/null
+++ b/lombok-intro/pom.xml
@@ -0,0 +1,151 @@
+
+
+
+ 4.0.0
+
+ lombok-intro
+
+ com.baeldung
+ lombok-intro
+ 0.1-SNAPSHOT
+
+
+
+
+ org.projectlombok
+ lombok
+
+ ${lombok.version}
+ provided
+
+
+
+ org.hibernate.javax.persistence
+ hibernate-jpa-2.1-api
+ ${hibernate-jpa-2.1-api.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${org.slf4j.version}
+
+
+
+ ch.qos.logback
+ logback-core
+ ${logback.version}
+ runtime
+
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+
+ lombok-intro
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ ${maven.compiler.target}
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+
+ org.projectlombok
+ lombok-maven-plugin
+ ${delombok-maven-plugin.version}
+
+
+ delombok
+ generate-sources
+
+ delombok
+
+
+ ${project.basedir}/src/main/java
+ false
+
+ skip
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+ UTF-8
+
+ 1.8
+ 1.8
+
+
+ 1.16.8
+
+
+ 1.0.0.Final
+
+
+ 1.7.13
+ 1.1.3
+
+
+ 4.12
+
+
+ 3.5.1
+ 2.19.1
+
+
+ ${lombok.version}.0
+
+
+
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/ApiClientConfiguration.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/ApiClientConfiguration.java
new file mode 100644
index 0000000000..74cc929d32
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/ApiClientConfiguration.java
@@ -0,0 +1,22 @@
+package com.baeldung.lombok.intro;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Builder
+@Slf4j
+@Getter
+public class ApiClientConfiguration {
+
+ private String host;
+ private int port;
+ private boolean useHttps;
+
+ private long connectTimeout;
+ private long readTimeout;
+
+ private String username;
+ private String password;
+
+}
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/ContactInformationSupport.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/ContactInformationSupport.java
new file mode 100644
index 0000000000..ea9c3d23f5
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/ContactInformationSupport.java
@@ -0,0 +1,17 @@
+package com.baeldung.lombok.intro;
+
+import lombok.Data;
+
+@Data
+public class ContactInformationSupport implements HasContactInformation {
+
+ private String firstName;
+ private String lastName;
+ private String phoneNr;
+
+ @Override
+ public String getFullName() {
+ return getFirstName() + " " + getLastName();
+ }
+
+}
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/HasContactInformation.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/HasContactInformation.java
new file mode 100644
index 0000000000..9128df5fb0
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/HasContactInformation.java
@@ -0,0 +1,16 @@
+package com.baeldung.lombok.intro;
+
+public interface HasContactInformation {
+
+ String getFirstName();
+ void setFirstName(String firstName);
+
+ String getFullName();
+
+ String getLastName();
+ void setLastName(String lastName);
+
+ String getPhoneNr();
+ void setPhoneNr(String phoneNr);
+
+}
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/LoginResult.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/LoginResult.java
new file mode 100644
index 0000000000..6e75696612
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/LoginResult.java
@@ -0,0 +1,25 @@
+package com.baeldung.lombok.intro;
+
+import java.net.URL;
+import java.time.Duration;
+import java.time.Instant;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Accessors;
+
+@RequiredArgsConstructor
+@Accessors(fluent = true) @Getter
+@EqualsAndHashCode(of = {"authToken"})
+public class LoginResult {
+
+ private final @NonNull Instant loginTs;
+
+ private final @NonNull String authToken;
+ private final @NonNull Duration tokenValidity;
+
+ private final @NonNull URL tokenRefreshUrl;
+
+}
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/User.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/User.java
new file mode 100644
index 0000000000..d032d1f9e7
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/User.java
@@ -0,0 +1,43 @@
+package com.baeldung.lombok.intro;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.experimental.Delegate;
+
+@Entity
+@Getter @Setter @NoArgsConstructor // <--- THIS is it
+@ToString(exclude = {"events"})
+public class User implements Serializable, HasContactInformation {
+
+ private @Id @Setter(AccessLevel.PROTECTED) Long id; // will be set when persisting
+
+ private String nickname;
+
+ // Whichever other User-specific attributes
+
+ @Delegate(types = {HasContactInformation.class})
+ private final ContactInformationSupport contactInformation = new ContactInformationSupport();
+
+ // User itelf will implement all contact information by delegation
+
+ @OneToMany(mappedBy = "user")
+ private List events;
+
+ public User(String nickname, String firstName, String lastName, String phoneNr) {
+ this.nickname = nickname;
+ contactInformation.setFirstName(firstName);
+ contactInformation.setLastName(lastName);
+ contactInformation.setPhoneNr(phoneNr);
+ }
+
+}
diff --git a/lombok-intro/src/main/java/com/baeldung/lombok/intro/UserEvent.java b/lombok-intro/src/main/java/com/baeldung/lombok/intro/UserEvent.java
new file mode 100644
index 0000000000..6a13608664
--- /dev/null
+++ b/lombok-intro/src/main/java/com/baeldung/lombok/intro/UserEvent.java
@@ -0,0 +1,29 @@
+package com.baeldung.lombok.intro;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@NoArgsConstructor @Getter @Setter
+public class UserEvent implements Serializable {
+
+ // This class is just for sample purposes.
+
+ private @Id @Setter(AccessLevel.PROTECTED) Long id;
+
+ @ManyToOne
+ private User user;
+
+ public UserEvent(User user) {
+ this.user = user;
+ }
+
+}
diff --git a/lombok-intro/src/test/java/com/baeldung/lombok/intro/ApiClientConfigurationTest.java b/lombok-intro/src/test/java/com/baeldung/lombok/intro/ApiClientConfigurationTest.java
new file mode 100644
index 0000000000..8283fc655e
--- /dev/null
+++ b/lombok-intro/src/test/java/com/baeldung/lombok/intro/ApiClientConfigurationTest.java
@@ -0,0 +1,43 @@
+package com.baeldung.lombok.intro;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import com.baeldung.lombok.intro.ApiClientConfiguration.ApiClientConfigurationBuilder;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ApiClientConfigurationTest {
+
+ @Test
+ public void givenAnnotatedConfiguration_thenCanBeBuiltViaBuilder() {
+ ApiClientConfiguration config =
+ new ApiClientConfigurationBuilder()
+ .host("api.server.com")
+ .port(443)
+ .useHttps(true)
+ .connectTimeout(15_000L)
+ .readTimeout(5_000L)
+ .username("myusername")
+ .password("secret")
+ .build();
+
+ Assert.assertEquals(config.getHost(), "api.server.com");
+ Assert.assertEquals(config.getPort(), 443);
+ Assert.assertEquals(config.isUseHttps(), true);
+ Assert.assertEquals(config.getConnectTimeout(), 15_000L);
+ Assert.assertEquals(config.getReadTimeout(), 5_000L);
+ Assert.assertEquals(config.getUsername(), "myusername");
+ Assert.assertEquals(config.getPassword(), "secret");
+ }
+
+ @Test
+ public void givenAnnotatedConfiguration_thenHasLoggerInstance() throws NoSuchFieldException {
+ Field loggerInstance = ApiClientConfiguration.class.getDeclaredField("log");
+ int modifiers = loggerInstance.getModifiers();
+ Assert.assertTrue(Modifier.isPrivate(modifiers));
+ Assert.assertTrue(Modifier.isStatic(modifiers));
+ Assert.assertTrue(Modifier.isFinal(modifiers));
+ }
+
+}
diff --git a/lombok-intro/src/test/java/com/baeldung/lombok/intro/LoginResultTest.java b/lombok-intro/src/test/java/com/baeldung/lombok/intro/LoginResultTest.java
new file mode 100644
index 0000000000..56878e4a03
--- /dev/null
+++ b/lombok-intro/src/test/java/com/baeldung/lombok/intro/LoginResultTest.java
@@ -0,0 +1,59 @@
+package com.baeldung.lombok.intro;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.time.Duration;
+import java.time.Instant;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LoginResultTest {
+
+ @Test
+ public void givenAnnotatedLoginResult_thenHasConstructorForAllFinalFields()
+ throws MalformedURLException {
+ /* LoginResult loginResult = */ new LoginResult(
+ Instant.now(),
+ "apitoken",
+ Duration.ofHours(1),
+ new URL("https://api.product.com/token-refresh"));
+ }
+
+ @Test
+ public void givenAnnotatedLoginResult_thenHasFluentGetters()
+ throws MalformedURLException {
+ Instant loginTs = Instant.now();
+ LoginResult loginResult = new LoginResult(
+ loginTs,
+ "apitoken",
+ Duration.ofHours(1),
+ new URL("https://api.product.com/token-refresh"));
+
+ Assert.assertEquals(loginResult.loginTs(), loginTs);
+ Assert.assertEquals(loginResult.authToken(), "apitoken");
+ Assert.assertEquals(loginResult.tokenValidity(), Duration.ofHours(1));
+ Assert.assertEquals(loginResult.tokenRefreshUrl(), new URL("https://api.product.com/token-refresh"));
+ }
+
+ @Test
+ public void givenAnnotatedLoginResult_whenSameApiToken_thenEqualInstances()
+ throws MalformedURLException {
+ String theSameApiToken = "testapitoken";
+
+ LoginResult loginResult1 = new LoginResult(
+ Instant.now(),
+ theSameApiToken,
+ Duration.ofHours(1),
+ new URL("https://api.product.com/token-refresh"));
+
+ LoginResult loginResult2 = new LoginResult(
+ Instant.now(),
+ theSameApiToken,
+ Duration.ofHours(2),
+ new URL("https://api.product.com/token-refresh-alt"));
+
+ Assert.assertEquals(loginResult1, loginResult2);
+ }
+
+}
diff --git a/lombok-intro/src/test/java/com/baeldung/lombok/intro/UserTest.java b/lombok-intro/src/test/java/com/baeldung/lombok/intro/UserTest.java
new file mode 100644
index 0000000000..b3bf21478f
--- /dev/null
+++ b/lombok-intro/src/test/java/com/baeldung/lombok/intro/UserTest.java
@@ -0,0 +1,73 @@
+package com.baeldung.lombok.intro;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UserTest {
+
+ @Test
+ public void givenAnnotatedUser_thenHasEmptyConstructor() {
+ /* User user = */ new User();
+ }
+
+ @Test
+ public void givenAnnotatedUser_thenHasGettersAndSetters() {
+ User user = new User("testnickname", "Test", "JUnit", "123456");
+
+ Assert.assertEquals("testnickname", user.getNickname());
+ Assert.assertEquals("Test", user.getFirstName());
+ Assert.assertEquals("JUnit", user.getLastName());
+ Assert.assertEquals("123456", user.getPhoneNr());
+
+ user.setNickname("testnickname2");
+ user.setFirstName("Test2");
+ user.setLastName("JUnit2");
+ user.setPhoneNr("654321");
+
+ Assert.assertEquals("testnickname2", user.getNickname());
+ Assert.assertEquals("Test2", user.getFirstName());
+ Assert.assertEquals("JUnit2", user.getLastName());
+ Assert.assertEquals("654321", user.getPhoneNr());
+ }
+
+ @Test
+ public void givenAnnotatedUser_thenHasProtectedSetId() throws NoSuchMethodException {
+ Method setIdMethod = User.class.getDeclaredMethod("setId", Long.class);
+ int modifiers = setIdMethod.getModifiers();
+ Assert.assertTrue(Modifier.isProtected(modifiers));
+ }
+
+ @Test
+ public void givenAnnotatedUser_thenImplementsHasContactInformation() {
+ User user = new User("testnickname3", "Test3", "JUnit3", "987654");
+ Assert.assertTrue(user instanceof HasContactInformation);
+
+ Assert.assertEquals("Test3", user.getFirstName());
+ Assert.assertEquals("JUnit3", user.getLastName());
+ Assert.assertEquals("987654", user.getPhoneNr());
+ Assert.assertEquals("Test3 JUnit3", user.getFullName());
+
+ user.setFirstName("Test4");
+ user.setLastName("JUnit4");
+ user.setPhoneNr("456789");
+
+ Assert.assertEquals("Test4", user.getFirstName());
+ Assert.assertEquals("JUnit4", user.getLastName());
+ Assert.assertEquals("456789", user.getPhoneNr());
+ Assert.assertEquals("Test4 JUnit4", user.getFullName());
+ }
+
+ @Test
+ public void givenAnnotatedUser_whenHasEvents_thenToStringDumpsNoEvents() {
+ User user = new User("testnickname", "Test", "JUnit", "123456");
+ List events = Arrays.asList(new UserEvent(user), new UserEvent(user));
+ user.setEvents(events);
+ Assert.assertFalse(user.toString().contains("events"));
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index ce7dfca62f..9abd2d9376 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,8 @@
spring-zuul
jsf
xml
+
+ lombok-intro