Sunday, 30 December 2018

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly


Caused by: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:556)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:286)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.yardbud.service.OrderServiceImpl$$EnhancerBySpringCGLIB$$6ebf61a8.save()
at com.yardbud.service.OrderServiceTest.whenSaveEmptyOrder_ThenReturnException(OrderServiceTest.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
... 21 more
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
... 39 more


The exception above is due to following 'transactional' setup:

Service: save method is marked as transactional.
A:

@Service@Transactionalpublic class OrderServiceImpl implements OrderService {

    @Autowired    private OrderRepository orderRepository;
    @Override    @Transactional    public Order save(Order order) throws ConstrainViolationException {
        Order saved;        try {
            saved = orderRepository.save(order);        } catch (ConstraintViolationException e) {
            throw new ConstrainViolationException(e.getMessage());        }
        return saved;    }

In its unit test, the test method modifier @Transactional is removed
B:

@Test(expected = ConstrainViolationException.class)
//@Transactionalpublic void whenSaveEmptyOrder_ThenReturnException() throws ConstrainViolationException {

    orderService.save(Order.builder()
            .searcher(new Searcher())
            .lister(new Lister("Yichun", "Zhao"))
            .startTime(ZonedDateTime.now())
            .endTime(ZonedDateTime.now().plusDays(100))
            .build()
    );}


I didn't get why





Friday, 28 December 2018

SpringBootTest webEnvironment

For the spring boot test, the default value for the 'webEnvironment' is 'MOCK';


@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE )
public class OrderServiceTest {
    @Autowired


A Spring Boot application is a Spring ApplicationContext, so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context.
[Note]
External properties, logging, and other features of Spring Boot are installed in the context by default only if you use SpringApplication to create it.
Spring Boot provides a @SpringBootTest annotation, which can be used as an alternative to the standard spring-test @ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests through SpringApplication. In addition to@SpringBootTest a number of other annotations are also provided for testing more specific slices of an application.
[Tip]
If you are using JUnit 4, don’t forget to also add @RunWith(SpringRunner.class) to your test, otherwise the annotations will be ignored. If you are using JUnit 5, there’s no need to add the equivalent @ExtendWith(SpringExtension) as @SpringBootTest and the other @…Test annotations are already annotated with it.
By default, @SpringBootTest will not start a server. You can use the webEnvironment attribute of @SpringBootTest to further refine how your tests run:
  • MOCK(Default) : Loads a web ApplicationContext and provides a mock web environment. Embedded servers are not started when using this annotation. If a web environment is not available on your classpath, this mode transparently falls back to creating a regular non-web ApplicationContext. It can be used in conjunction with @AutoConfigureMockMvc or @AutoConfigureWebTestClient for mock-based testing of your web application.
  • RANDOM_PORT: Loads a WebServerApplicationContext and provides a real web environment. Embedded servers are started and listen on a random port.
  • DEFINED_PORT: Loads a WebServerApplicationContext and provides a real web environment. Embedded servers are started and listen on a defined port (from your application.properties) or on the default port of 8080.
  • NONE: Loads an ApplicationContext by using SpringApplication but does not provide any web environment (mock or otherwise).
[Note]
If your test is @Transactional, it rolls back the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case.


[Note]
@SpringBootTest with webEnvironment = WebEnvironment.RANDOM_PORT will also start the management server on a separate random port if your application uses a different port for the management server.
Reference:

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html


Thursday, 27 December 2018

javax.validation.ConstraintViolationException

javax.validation.ConstraintViolationException: Validation failed for classes [com.yardbud.entities.LoginInfo] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=loginInfo.email, rootBeanClass=class com.yardbud.entities.Lister, messageTemplate='{javax.validation.constraints.NotNull.message}'}
ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=loginInfo.password, rootBeanClass=class com.yardbud.entities.Lister, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]

This is due to entity field value is validated before it is persisted. So checking the input values into the data model. 


@Embedded@Validprotected LoginInfo loginInfo;

@NotNull@Column(name = "PASS_WORD")
protected String password;

org.springframework.dao.InvalidDataAccessApiUsageException:


org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.yardbud.entities.Order.lister -> com.yardbud.entities.Lister; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.yardbud.entities.Order.lister -> com.yardbud.entities.Lister

Data object A has one data object b; object A has one data object c. 
Adding the cascade type attribute into the one-to-one relationship solved the exception above.

@OneToOne(cascade = CascadeType.ALL)

Wednesday, 26 December 2018

Decorator Pattern

The decorator is a structural pattern, mainly used as handling legacy code. It allows a user to add or remove a functionality to an existing object in runtime. It works as a wrapper class that wraps an existing class and offers new functionality, and it may be removed afterward.




Can Jackson Deserialize Java Time ZonedDateTime

Yes, but must include JSR310. Thus ZonedDateTime can be deserialized directly from JSON response to POJO field. <dependency> <g...