Giter Site home page Giter Site logo

book-microservices-v2 / chapter03 Goto Github PK

View Code? Open in Web Editor NEW
29.0 4.0 19.0 170 KB

Learn Microservices with Spring Boot (2nd edition) - Chapter 3

Home Page: https://tpd.io/book-extra

Java 100.00%
microservices java spring-boot architecture book learn-microservices modular-monolith tdd bdd mockito

chapter03's Introduction

Learn Microservices with Spring Boot - Chapter 3

This repository contains the source code of the practical use case described in the book Learn Microservices with Spring Boot (2nd Edition).

The book follows a pragmatic approach to building a Microservice Architecture. You start with a small monolith and examine the pros and cons that come with a move to microservices.

Chapter 3 version

In Chapter 3, the goal is to build a Spring Boot application according to good practices:

  • Domain-Driven Design. We analyze the boundaries of the Users and Challenges domains.
  • 3-layer Application Design. This chapter focuses on two of the layers: Controller, and Service.
  • Test-Driven Development. You write tests before building the functionalities.
  • Monolith First. We keep two domains separate by using different root packages.

The next figure shows the status of the Multiplication application by the end of the Chapter, as it's also included in this repository.

Multiplication application - Logical View - Chapter 3

There are two functional domains included in this first application: Users, and Challenges. See the figure below.

Multiplication application - Domains

Running the app

Note: You need to use at least JDK version 14 to run this project.

To start the Spring Boot application, you can use the command line with the included Maven wrapper:

$ ./mvnw spring-boot:run

Questions

  • Do you have questions about how to make this application work?
  • Did you get the book and have questions about any concept explained within this chapter?
  • Have you found issues using updated dependencies?

Don't hesitate to create an issue in this repository and post your question/problem there.

About the book

Are you interested in building a microservice architecture from scratch? You'll face all the challenges of designing and implementing a distributed system one by one, and will be able to evaluate if it's the best choice for your project.

Visit https://tpd.io/book-extra for all the details about the book.

Purchase

You can buy the book online from these stores:

Source code by chapter (all repositories are available on Github)

Extra chapters:

chapter03's People

Contributors

mechero avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

chapter03's Issues

Running of test fails - Mockito cannot mock class

Unfortunately, I am stuck already at page 47 of the book. When running ./mvnw test I am getting this error log

`-------------------------------------------------------------------------------
Test set: microservices.book.multiplication.challenge.ChallengeGeneratorServiceTest

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.037 s <<< FAILURE! - in microservices.book.multiplication.challenge.ChallengeGeneratorServiceTest
generateRandomFactorIsBetweenExpectedLimits Time elapsed: 0.036 s <<< ERROR!
org.mockito.exceptions.base.MockitoException:
Unable to initialize @SPY annotated field 'random'.

Mockito cannot mock this class: class java.util.Random.

Mockito can only mock non-private & non-final classes, but the root cause of this error might be different.
Please check the full stacktrace to understand what the issue is.
If you're still not sure why you're getting this error, please open an issue on GitHub.

Java : 17
JVM vendor name : Eclipse Adoptium
JVM vendor version : 17.0.5+8
JVM name : OpenJDK 64-Bit Server VM
JVM version : 17.0.5+8
JVM info : mixed mode
OS name : Linux
OS version : 5.15.0-56-generic

Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract boolean jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.isStochastic()
Caused by: org.mockito.exceptions.base.MockitoException:

Mockito cannot mock this class: class java.util.Random.

Mockito can only mock non-private & non-final classes, but the root cause of this error might be different.
Please check the full stacktrace to understand what the issue is.
If you're still not sure why you're getting this error, please open an issue on GitHub.

Java : 17
JVM vendor name : Eclipse Adoptium
JVM vendor version : 17.0.5+8
JVM name : OpenJDK 64-Bit Server VM
JVM version : 17.0.5+8
JVM info : mixed mode
OS name : Linux
OS version : 5.15.0-56-generic

Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract boolean jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.isStochastic()
Caused by: java.lang.IllegalStateException: Cannot access annotation property public abstract boolean jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.isStochastic()
Caused by: java.lang.IllegalAccessException: class net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation cannot access interface jdk.internal.util.random.RandomSupport$RandomGeneratorProperties (in module java.base) because module java.base does not export jdk.internal.util.random to unnamed module @55a561cf

`
I am not able to solve the issue. Seems to be an incompatibility issue between the Java version and Mockito? Not sure, how to solve this.

Parameters selected in spring initializr:

Spring Boot 3.0.1
Java 17 (also tested with 19)

I saw some hints to add an explicit dependency for Mockito into pom.xml but this actually does not help as it is unclear which version fits to Java 17 or 19 (is there any version which fits?)

JUnit output in book incorrect?

Looking at listing 3-12 on page 47, it says it Actual is null, and Expected is factorA=20, factorB=30. I believe the Expected should be factorA=31, factorB=41. I actually downloaded the code just to debug the test to double check this. Am I correct or am I missing something?

Error while running ChallengeGeneratorServiceTest

Hi- Getting the following error while running the ChallengeGeneratorServiceTest .

org.mockito.exceptions.base.MockitoException: Unable to initialize @SPY annotated field 'random'.

Mockito cannot mock this class: class java.util.Random.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.

Java : 18
JVM vendor name : Oracle Corporation
JVM vendor version : 18.0.1.1+2-6
JVM name : OpenJDK 64-Bit Server VM
JVM version : 18.0.1.1+2-6
JVM info : mixed mode, sharing
OS name : Windows 10
OS version : 10.0

Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract java.lang.String jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.name()

at org.mockito.junit.jupiter.MockitoExtension.beforeEach(MockitoExtension.java:153)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$2(TestMethodTestDescriptor.java:163)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$6(TestMethodTestDescriptor.java:199)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:199)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:162)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:129)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Suppressed: java.lang.NullPointerException: Cannot invoke "java.util.Set.forEach(java.util.function.Consumer)" because the return value of "org.junit.jupiter.api.extension.ExtensionContext$Store.remove(Object, java.lang.Class)" is null
	at org.mockito.junit.jupiter.MockitoExtension.afterEach(MockitoExtension.java:184)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$12(TestMethodTestDescriptor.java:257)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:273)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$14(TestMethodTestDescriptor.java:273)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:272)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:256)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:141)
	... 47 more

Caused by: org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class java.util.Random.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.

Java : 18
JVM vendor name : Oracle Corporation
JVM vendor version : 18.0.1.1+2-6
JVM name : OpenJDK 64-Bit Server VM
JVM version : 18.0.1.1+2-6
JVM info : mixed mode, sharing
OS name : Windows 10
OS version : 10.0

Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract java.lang.String jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.name()
... 54 more
Caused by: java.lang.IllegalStateException: Cannot access annotation property public abstract java.lang.String jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.name()
at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.getValue(AnnotationDescription.java:824)
at net.bytebuddy.implementation.attribute.AnnotationAppender$Default.handle(AnnotationAppender.java:314)
at net.bytebuddy.implementation.attribute.AnnotationAppender$Default.doAppend(AnnotationAppender.java:377)
at net.bytebuddy.implementation.attribute.AnnotationAppender$Default.append(AnnotationAppender.java:354)
at net.bytebuddy.implementation.attribute.TypeAttributeAppender$ForInstrumentedType.apply(TypeAttributeAppender.java:93)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5916)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2213)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:232)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:204)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3668)
at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:288)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.lambda$mockClass$0(TypeCachingBytecodeGenerator.java:47)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:40)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:77)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:43)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:42)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:53)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:96)
at org.mockito.Mockito.mock(Mockito.java:1965)
at org.mockito.internal.configuration.SpyAnnotationEngine.spyNewInstance(SpyAnnotationEngine.java:130)
at org.mockito.internal.configuration.SpyAnnotationEngine.process(SpyAnnotationEngine.java:70)
at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:75)
at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:47)
at org.mockito.MockitoAnnotations.openMocks(MockitoAnnotations.java:81)
at org.mockito.internal.framework.DefaultMockitoSession.(DefaultMockitoSession.java:43)
at org.mockito.internal.session.DefaultMockitoSessionBuilder.startMocking(DefaultMockitoSessionBuilder.java:83)
... 54 more
Caused by: java.lang.IllegalAccessException: class net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation cannot access interface jdk.internal.util.random.RandomSupport$RandomGeneratorProperties (in module java.base) because module java.base does not export jdk.internal.util.random to unnamed module @71c7db30
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.getValue(AnnotationDescription.java:803)
... 83 more

Process finished with exit code -1

The constructor Challenge(int, int) is undefined

When I am running the test, I am getting this error:

The constructor Challenge(int, int) is undefined

It is caused by this line of code inside ChallengeGeneratorServiceTest

then(challenge).isEqualTo(new Challenge(31, 41));

It is possible to solve the issue by explicitly adding a constructor which accepts two int values to the Challenge class:

`package microservices.book.multiplication.challenge;

import lombok.*;

/**

  • This class represents a Challenge to solve a Multiplication (a * b).
    */
    @getter
    @tostring
    @EqualsAndHashCode
    @AllArgsConstructor
    public class Challenge {
    private int factorA;
    private int factorB;

    public Challenge(int i, int j) {
    this.factorA = i;
    this.factorB = j;
    }
    }`

However, as we use the @AllArgsConstructor of Lombock it should not be necessary to add this constructor. Am I missing something?

javax.validation cannot be resolved

Dear Moisés,

I had an issue while importing

javax.validation.constraints.*

for the ChallengeAttemptDTO. I found that this solves the issue:

jakarta.validation.constraints.*

Is this already documented somewhere, I do not find anything related to this on your web page.

Many thanks and best regards,
Matthias

http://localhost:8080/challenges/random not found

Hey Moisés,

I finished the implementation of the controller but when running the application with mvnw spring-boot:run there is nothing found under http://localhost:8080/challenges/random. I only receive this error:

`This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun Jan 15 16:48:24 CET 2023
There was an unexpected error (type=Not Found, status=404).`

I do not see what could be the error in my code which causes the issue. Maybe you want to have a look into my coding on GitHub.

Thanks and best regards,
Matthias

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.