From dc06936a5d22cbb5a09ac5488af58d30b1c90ad3 Mon Sep 17 00:00:00 2001 From: SauDev Date: Fri, 17 Jul 2020 11:43:25 +0530 Subject: [PATCH] BAEL-4135 - When are static variables initialized? (#9607) * Hexagonal Architecture in Java A quick and practical example of Hexagonal Architecture in Java * Fixed code formatting issues * When are static variables initialized Sample class and test class. * Revert "When are static variables initialized" This reverts commit c781923093ccc88bc269bea276653169065cb17b. * Revert "Revert "When are static variables initialized"" This reverts commit 2bffdf401d4e7dc2cefd7eb16357b2d51271edad. * New java module for static variable Created a new core-java-lang-3 module for static variables. * PR review changes: Added more scenarios to the static variable test Covered the following cases: 1. Variable initialization in a static block 2. Variable initialization in a static nested class --- core-java-modules/core-java-lang-3/pom.xml | 2 +- .../staticvariables/StaticVariableDemo.java | 23 ++++ .../StaticVariableUnitTest.java | 113 ++++++++++++++++++ patterns/hexagonal-architecture/pom.xml | 59 +++++++++ .../hexagonal/HexArchApplicationDemo.java | 13 ++ .../pattern/hexagonal/config/AppConfig.java | 15 +++ .../pattern/hexagonal/config/MongoConfig.java | 10 ++ .../controller/EmployeeController.java | 25 ++++ .../hexagonal/domain/model/Employee.java | 51 ++++++++ .../domain/services/EmployeeService.java | 10 ++ .../domain/services/EmployeeServiceImpl.java | 34 ++++++ .../persistence/EmployeeRepository.java | 15 +++ .../persistence/MongoDBRepository.java | 24 ++++ .../hexagonal/persistence/MongoRepoEx.java | 9 ++ .../src/main/resources/application.properties | 1 + .../services/EmployeeServiceImplTest.java | 46 +++++++ 16 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 core-java-modules/core-java-lang-3/src/main/java/com/baeldung/staticvariables/StaticVariableDemo.java create mode 100644 core-java-modules/core-java-lang-3/src/test/java/com/baeldung/staticvariables/StaticVariableUnitTest.java create mode 100644 patterns/hexagonal-architecture/pom.xml create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java create mode 100644 patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java create mode 100644 patterns/hexagonal-architecture/src/main/resources/application.properties create mode 100644 patterns/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplTest.java diff --git a/core-java-modules/core-java-lang-3/pom.xml b/core-java-modules/core-java-lang-3/pom.xml index 2a2856a80a..de290717b1 100644 --- a/core-java-modules/core-java-lang-3/pom.xml +++ b/core-java-modules/core-java-lang-3/pom.xml @@ -39,4 +39,4 @@ 3.12.2 - + \ No newline at end of file diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/staticvariables/StaticVariableDemo.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/staticvariables/StaticVariableDemo.java new file mode 100644 index 0000000000..917e9b0953 --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/staticvariables/StaticVariableDemo.java @@ -0,0 +1,23 @@ +package com.baeldung.staticvariables; + +public class StaticVariableDemo { + public static int i; + public static int j = 20; + public static int z; + + static { + z = 30; + a = 40; + } + + public static int a = 50; + + public static final int b = 100; + + public StaticVariableDemo() { + } + + static class Nested { + public static String nestedClassStaticVariable = "test"; + } +} diff --git a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/staticvariables/StaticVariableUnitTest.java b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/staticvariables/StaticVariableUnitTest.java new file mode 100644 index 0000000000..06711a888b --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/staticvariables/StaticVariableUnitTest.java @@ -0,0 +1,113 @@ +package com.baeldung.staticvariables; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.Test; + +public class StaticVariableUnitTest { + + @Test + public void initializeStaticVariable_checkAssignedValues() { + + try { + Class staticVariableDemo = this.getClass() + .getClassLoader() + .loadClass("com.baeldung.staticvariables.StaticVariableDemo"); + + Field field1 = staticVariableDemo.getField("i"); + + assertThat(field1.getInt(staticVariableDemo)).isEqualTo(0); + + Field field2 = staticVariableDemo.getField("j"); + + assertThat(field2.getInt(staticVariableDemo)).isEqualTo(20); + + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } + + @Test + public void initializeStaticVariable_checkStaticBlock() { + + try { + Class staticVariableDemo = this.getClass() + .getClassLoader() + .loadClass("com.baeldung.staticvariables.StaticVariableDemo"); + + Field field1 = staticVariableDemo.getField("z"); + + assertThat(field1.getInt(staticVariableDemo)).isEqualTo(30); + + Field field2 = staticVariableDemo.getField("a"); + + assertThat(field2.getInt(staticVariableDemo)).isEqualTo(50); + + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } + + @Test + public void initializeStaticVariable_checkFinalValues() { + + try { + Class staticVariableDemo = this.getClass() + .getClassLoader() + .loadClass("com.baeldung.staticvariables.StaticVariableDemo"); + + Field field1 = staticVariableDemo.getField("b"); + + assertThat(field1.getInt(staticVariableDemo)).isEqualTo(100); + + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } + + @Test + public void initializeStaticVariable_checkInnerClassValues() { + + try { + Class staticVariableDemo = this.getClass() + .getClassLoader() + .loadClass("com.baeldung.staticvariables.StaticVariableDemo"); + + Class[] nestedClasses = staticVariableDemo.getClasses(); + + for (Class nestedClass : nestedClasses) { + if (nestedClass.getName() + .equals("Nested")) { + + Field field1 = nestedClass.getField("nestedClassStaticVariable"); + assertThat(field1.get(nestedClass)).isEqualTo("test"); + } + } + + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } +} diff --git a/patterns/hexagonal-architecture/pom.xml b/patterns/hexagonal-architecture/pom.xml new file mode 100644 index 0000000000..9317a25e56 --- /dev/null +++ b/patterns/hexagonal-architecture/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + com.baeldung + hexagonal-architecture + 1.0 + hexagonal-architecture + Project for hexagonal architecture in java + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.mockito + mockito-core + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java new file mode 100644 index 0000000000..52aaefaaf7 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/HexArchApplicationDemo.java @@ -0,0 +1,13 @@ +package com.baeldung.pattern.hexagonal; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HexArchApplicationDemo { + + public static void main(String[] args) { + SpringApplication.run(HexArchApplicationDemo.class, args); + } + +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java new file mode 100644 index 0000000000..ee8a01d0e2 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/AppConfig.java @@ -0,0 +1,15 @@ +package com.baeldung.pattern.hexagonal.config; + +import com.baeldung.pattern.hexagonal.domain.services.EmployeeService; +import com.baeldung.pattern.hexagonal.domain.services.EmployeeServiceImpl; +import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AppConfig { + @Bean + public EmployeeService getEmployeeService(EmployeeRepository employeeRepository) { + return new EmployeeServiceImpl(employeeRepository); + } +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java new file mode 100644 index 0000000000..fa6980824a --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/config/MongoConfig.java @@ -0,0 +1,10 @@ +package com.baeldung.pattern.hexagonal.config; + +import com.baeldung.pattern.hexagonal.persistence.MongoRepoEx; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@Configuration +@EnableMongoRepositories(basePackageClasses = MongoRepoEx.class) +public class MongoConfig { +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java new file mode 100644 index 0000000000..077fc6fdea --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/controller/EmployeeController.java @@ -0,0 +1,25 @@ +package com.baeldung.pattern.hexagonal.controller; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import com.baeldung.pattern.hexagonal.domain.services.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/employees") +public class EmployeeController { + @Autowired + EmployeeService employeeService; + + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Employee addEmployee(@RequestBody Employee employee) { + return employeeService.addEmployee(employee); + } + + @GetMapping(path = "/{employeeId}") + public Employee getEmployee(@PathVariable("employeeId") String employeeId) { + return employeeService.getEmployee(employeeId); + } +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java new file mode 100644 index 0000000000..de1f15cf53 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/model/Employee.java @@ -0,0 +1,51 @@ +package com.baeldung.pattern.hexagonal.domain.model; + +import org.springframework.data.annotation.Id; + +import java.util.Objects; + +public class Employee { + @Id + private String empId; + private String empName; + private String empJobTitle; + + public String getEmpId() { + return empId; + } + + public void setEmpId(String empId) { + this.empId = empId; + } + + public String getEmpName() { + return empName; + } + + public void setEmpName(String empName) { + this.empName = empName; + } + + public String getEmpJobTitle() { + return empJobTitle; + } + + public void setEmpJobTitle(String empJobTitle) { + this.empJobTitle = empJobTitle; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Employee employee = (Employee) o; + return empId.equals(employee.empId); + } + + @Override + public int hashCode() { + return Objects.hash(empId); + } +} \ No newline at end of file diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java new file mode 100644 index 0000000000..902abefabb --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeService.java @@ -0,0 +1,10 @@ +package com.baeldung.pattern.hexagonal.domain.services; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; + +public interface EmployeeService { + + Employee addEmployee(Employee employee); + + Employee getEmployee(String employeeId); +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java new file mode 100644 index 0000000000..cd7c30ff30 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImpl.java @@ -0,0 +1,34 @@ +package com.baeldung.pattern.hexagonal.domain.services; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Optional; + +public class EmployeeServiceImpl implements EmployeeService { + + private EmployeeRepository employeeRepository; + + @Autowired + public EmployeeServiceImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + @Override + public Employee addEmployee(Employee employee) { + return employeeRepository.add(employee); + } + + @Override + public Employee getEmployee(String employeeId) { + Optional employee = employeeRepository.findById(employeeId); + + if (employee.isPresent()) { + return employee.get(); + } else { + // throw + } + return null; + } +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java new file mode 100644 index 0000000000..53b4b6d276 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/EmployeeRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.pattern.hexagonal.persistence; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface EmployeeRepository { + + Employee add(Employee employee); + + Optional findById(String id); + +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java new file mode 100644 index 0000000000..08f0c96ab0 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoDBRepository.java @@ -0,0 +1,24 @@ +package com.baeldung.pattern.hexagonal.persistence; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public class MongoDBRepository implements EmployeeRepository { + + @Autowired + MongoRepoEx mongoRepository; + + @Override + public Employee add(Employee employee) { + return mongoRepository.insert(employee); + } + + @Override + public Optional findById(String id) { + return mongoRepository.findById(id); + } +} diff --git a/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java new file mode 100644 index 0000000000..766444c22f --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/java/com/baeldung/pattern/hexagonal/persistence/MongoRepoEx.java @@ -0,0 +1,9 @@ +package com.baeldung.pattern.hexagonal.persistence; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MongoRepoEx extends MongoRepository { +} diff --git a/patterns/hexagonal-architecture/src/main/resources/application.properties b/patterns/hexagonal-architecture/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/patterns/hexagonal-architecture/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/patterns/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplTest.java b/patterns/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplTest.java new file mode 100644 index 0000000000..cadb3b094b --- /dev/null +++ b/patterns/hexagonal-architecture/src/test/java/com/baeldung/pattern/hexagonal/domain/services/EmployeeServiceImplTest.java @@ -0,0 +1,46 @@ +package com.baeldung.pattern.hexagonal.domain.services; + +import com.baeldung.pattern.hexagonal.domain.model.Employee; +import com.baeldung.pattern.hexagonal.persistence.EmployeeRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class EmployeeServiceImplTest { + + private EmployeeRepository employeeRepository; + private EmployeeService testService; + private Employee testModel; + + @BeforeEach + void setUp() { + employeeRepository = mock(EmployeeRepository.class); + + testService = new EmployeeServiceImpl(employeeRepository); + testModel = new Employee(); + testModel.setEmpId("2000"); + testModel.setEmpName("Test user 1"); + testModel.setEmpJobTitle("Software engineer"); + } + + @Test + void addEmployee() { + when(employeeRepository.add(any(Employee.class))).thenReturn(testModel); + + Employee testResponse = testService.addEmployee(testModel); + assertEquals(testModel, testResponse); + } + + @Test + void getEmployee() { + when(employeeRepository.findById("2000")).thenReturn(Optional.of(testModel)); + + Employee testResponse = testService.getEmployee("2000"); + assertEquals(testModel, testResponse); + } +} \ No newline at end of file