JavaEE workshop #5

Kuba Hejda

(Mapstruct, Transactions, Testing)

Previous workshop

  • Exception handling
  • Logging
  • Testing - start

Content

  • Mapstruct
  • Proxy pattern
  • Transactions
  • JUnit, Mocks

Mapstruct

  • Widely used library to generate mappings
  • https://mapstruct.org
  • Supports spring - created mapper is a bean
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>${mapstruct.version}</version>
		</dependency>
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<configuration>
		<source>17</source>
		<release>17</release>
		<compilerArgument>-parameters</compilerArgument>
		<annotationProcessorPaths>
			<path>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
				<version>${lombok.version}</version>
			</path>
			<path>
				<groupId>org.mapstruct</groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>${mapstruct.version}</version>
			</path>
		</annotationProcessorPaths>
		<compilerArgs>
			<compilerArg>
				-Amapstruct.defaultComponentModel=spring
			</compilerArg>
		</compilerArgs>
	</configuration>
</plugin>
  • creates a surrogate, or placeholder class. Proxy instances accept requests from client objects, pass them to the underlying object and return the results. Proxies can improve efficiency and enhance functionality.

Java EE transactions

    public void moveMoney(Account senderAccount,
                          Account receiverAccount,
                          int amount) {
	//load sender and receiver and check sender has enough money
        
        receiver.money += amount;
        accountRepository.save(receiverAccount);

	//checking sender has enough money again because it could decrease in the meantime
        if (sender.money >= amount) {
            sender.money -= amount;
            accountRepository.save(senderAccount);
        } else {
            throw new RuntimeException("Sender has not enough money!");
        }
        
    }

What are they good for?

Java EE transactions

  • Global (distributed) transactions
    • work with multiple transactional resources, typically relational databases and message queues.
    • Managed by application server - cumbersome API
  • Local transactions
    • resource-specific, such as a transaction associated with a JDBC connection
    • they cannot work across multiple transactional resources.

Java EE transactions

  • ACID
    • atomicity - all commands are as one
    • consistency - leads from one consistent state to another
    • isolation - in concurrent environment commands behaves as they are performed sequentially
    • durability - a commited transaction means the new state will remain even in a case of the system failure

Spring Framework’s consistent programming model

  • resolves the disadvantages of global and local transactions
  • provides both declarative and programmatic transaction management
  • enable consistent programming model in any environment
  • The key to the Spring transaction abstraction is the notion of a transaction strategy. A transaction strategy is defined by the org.springframework.transaction.PlatformTransactionManager.
  • Defining the correct PlatformTransactionManager implementation is absolutely essential. There are more implemetations, e.g. JtaTransactionManager, DataSourceTransactionManager, HibernateTransactionManager

TransactionDefinition interface

  • Isolation: The degree to which this transaction is isolated from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?
  • Propagation: Typically, all code executed within a transaction scope will run in that transaction. However, you have the option of specifying the behavior in the event that a transactional method is executed when a transaction context already exists. For example, code can continue running in the existing transaction (the common case); or the existing transaction can be suspended and a new transaction created. Spring offers all of the transaction propagation options familiar from EJB CMT.
  • Timeout: limit for timing out and being rolled back automatically by the underlying transaction infrastructure.
  • Read-only status:  use when reads but does not modify data. Read-only transactions can be a useful optimization in some cases, such as when you are using Hibernate.
  • specify transaction behavior down to individual method

Rolling back a declarative transaction

  • In its default configuration, transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.
  • you can configure exactly which Exception types mark a transaction for rollback, including checked exceptions

Using @Transactional

  • @EnableTransactionManagement on @Configuration (not needed in Spring boot)
  • Method visibility - When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ if you need to annotate non-public methods.
  • Spring recommends that you only annotate concrete classes (and methods of concrete classes). @Transactional annotation on an interface (or an interface method), works only as you would expect it to if you are using interface-based proxies. With proxy-target-class="true" or the weaving-based aspect ( mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy.

Using @Transactional

  • @EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services

Java dynamic proxy

  • since version 1.3
  • A dynamic proxy is a run-time generated class, implementing one or more interfaces, that automatically converts every method call to one of those interfaces into a call to the invoke method on a provided implementation of 

 

java.runtime.InvocationHandler
  • byte code instrumentation library
  • used by Spring framework, Hibernate, Mockito
  • Enhancer - dynamically creates a subclass of a given type but intercepts all method calls.
  • allows the creation of Java proxies for non-interface types.
  • Missing manual
  • implementation of aspect-oriented programming for Java
  • weaver adds interception logic by directly modifying your bytecode of your class, either during build – compile time weaving (CTW) or when loading a class – load time weaving (LTW).

Aspect Oriented Programming

  • complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure.
  • OOP modularity = class, AOP = aspect
  • spring-aop = one of the key module of spring framework

AOP

Aspect modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java applications. In Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJ style).
Join point a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
Advice  action taken by an aspect at a particular join point. Different types of advice include "around," "before" and "after" advice. (Advice types are discussed below.) Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.

AOP

Pointcut a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.
Introduction declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)

AOP

Target object object being advised by one or more aspects. Also referred to as the advised object. Since Spring AOP is implemented using runtime proxies, this object will always be a proxied object.
AOP proxy an object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy.
Weaving linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.

Proxying in Spring

  • Java dynamic proxy
  • CGlib
  • AspectJ

Spring AOP - dynamic proxy

  • simplest solution (default)
  • no need for a special compilation process
  • Require "some" interface
  • supports only method execution join points (advising the execution of methods on Spring beans)
  • field interception is not implemented
  • work only with spring beans
  • Configuration mostly come from: <aop:config/>, <tx:annotation-driven/> (@EnableTransactionManagement), <aop:aspectj-autoproxy/> and <aop:scoped-proxy/>

Spring AOP with CGLIB

  • Spring AOP can also use CGLIB proxies
  • proxy classes rather than interfaces
  • CGLIB is used by default if a business object does not implement an interface
  • To force the use of CGLIB proxies set the value of the proxy-target-class attribute of the <aop:config> element to true:
<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

Spring AOP with AspectJ

  • spring ships with a small AspectJ aspect library
  • @Configurable - annotation marks a class as eligible for Spring-driven configuration. Autowiring spring beans to non-spring managed objects (instantied with "new" operator)
  • @Transactional - enable transaction support outside of the Spring container
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

Spring Transaction Management (spring-tx)

  • Consistent programming model across different transaction APIs such as Java Transaction API (JTA), JDBC, Hibernate, Java Persistence API (JPA), and Java Data Objects (JDO).
  • Support for declarative transaction management.
  • Simpler API for programmatic transaction management than complex transaction APIs such as JTA.
  • Excellent integration with Spring’s data access abstractions.

AOP - links

JUnit

  • testing support for spring framework application
  • support  integration testing without requiring deployment to your application server or connecting to other enterprise infrastructure
  • enables:
    • The correct wiring of your Spring IoC container contexts.
    • Data access using JDBC or an ORM tool. This would include such things as the correctness of SQL statements, Hibernate queries, JPA entity mappings, etc.
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

Stub

  • hand-written classes that mimic the dependency’s behavior
  • ​For example, a stub for an order repository can store orders in memory and return those orders as a result of search operations instead of querying a real database.

Mock

  • dynamic wrappers for dependencies
  • programmed with expectations of what exact method calls in what sequence the dependency should receive from a system under test (SUT) in order for the SUT to be deemed working correctly

Difference

Tests written with mocks usually follow an initialize -> set expectations -> exercise -> verifypattern to testing. While the pre-written stub would follow an initialize -> exercise -> verify.

Similarity

The purpose of both is to eliminate testing all the dependencies of a class or function so your tests are more focused and simpler in what they are trying to prove.

  • mocking framework
  • used to mock interfaces, spy implementations
  • ​dummy functionality can be added to a mock interface
  • uses Java Reflection in order to create mock objects
  • ​mock objects are proxy for actual implementations

Mockito - benefits

  • No Handwriting − No need to write mock objects on your own.
  • Refactoring Safe − Renaming interface method names or reordering parameters will not break the test code as Mocks are created at runtime.
  • Return value support − Supports return values.
  • Exception support − Supports exceptions.
  • Order check support − Supports check on order of method calls.
  • Annotation support − Supports creating mocks using annotation.

Mockito - features

  • offers simpler and more intuitive approach: you ask questions about interactions after execution.
  • mocks are often ready without expensive setup
  • very slim API
  • Mocks concrete classes as well as interfaces
  • Little annotation syntax sugar - @Mock
  • Verification errors are clean - click on stack trace to see failed verification in test; click on exception's cause to navigate to actual interaction in code. Stack trace is always clean.
  • Allows flexible verification in order (e.g: verify in order what you want, not every single interaction)
  • Supports exact-number-of-times and at-least-once verification
  • Flexible verification or stubbing using argument matchers (anyObject(), anyString() or refEq() for reflection-based equality matching)
  • Allows creating custom argument matchers or using existing hamcrest matchers
  • @Mock - create and inject mocked instances without having to call Mockito.mock manually.
  • @Spy - to spy on an existing instance
  • @Captor - o create an ArgumentCaptor instance.
  • @InjectMocks - o inject mock fields into the tested object automatically.

Q&A

ITA 08 - Workshop 05

By IT-absolvent

ITA 08 - Workshop 05

Workshop #5

  • 290