Kotlin allows you to put method implementation in an interface. The same mechanism can be found in Java interfaces as default methods (and also Groovy or Scala traits). Read more
Tag: java
Testing Kotlin with Spock Part 2 – Enum with instance method
Testing Kotlin with Spock Part 2 – Enum instance method
The enum class with instance method in Kotlin is quite similar to its Java version, but they are look a bit different Read more
MapStruct mapper injection in OSGi Blueprint
Deploy WSDL file as OSGI Bundle in Apache Karaf
Formatting Java Time with Spring Boot using JSON
The aim of this post is to summarize and review ways of formatting Java Time objects using Spring Boot and Jackson library.
This post is organized in five steps. Each step Read more
Do not use AllArgsConstructor in your public API
Introduction
Do you think about compatibility of your public API when you modify classes from it? It is especially easy to miss out that something incompatibly changed when you are using Lombok. If you useAllArgsConstructor
annotation it will cause many problems.
What is the problem?
Let's define simple class withAllArgsConstructor
:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; }Now we can use generated constructor in spock test:
def 'use generated allArgsConstructor'() { when: Person p = new Person('John', 'Smith', 30) then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } }And the test is green. Let's add new optional field to our Person class -
email
:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; private String email; }Adding optional field is considered compatible change. But our test fails...
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.github.alien11689.allargsconstructor.Person(java.lang.String, java.lang.String, java.lang.Integer)
How to solve this problem?
After adding field add previous constructor
If you still want to useAllArgsConstructor
you have to ensure compatibility by adding previous version of constructor on your own:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; private String email; public Person(String firstName, String lastName, Integer age) { this(firstName, lastName, age, null); } }And now our test again passes.
Annotation lombok.Data
is enough
If you use only Data
annotation, then constructor, with only mandatory (final
) fields, will be generated. It is because Data
implies RequiredArgsConstructor
:
@Data public class Person { private final String firstName; private final String lastName; private Integer age; }
class PersonTest extends Specification { def 'use generated requiredFieldConstructor'() { when: Person p = new Person('John', 'Smith') p.age = 30 then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } } }After adding new field
email
test still passes.
Use Builder
annotation
Annotation Builder
generates for us PersonBuilder
class which helps us create new Person
:
@Data @Builder public class Person { private final String firstName; private final String lastName; private Integer age; }
class PersonTest extends Specification { def 'use builder'() { when: Person p = Person.builder() .firstName('John') .lastName('Smith') .age(30).build() then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } } }After adding email field test still passes.
Conclusion
If you useAllArgsConstructor
you have to be sure what are you doing and know issues related to its compatibility. In my opinion the best option is not to use this annotation at all and instead stay with Data
or Builder
annotation.
Sources are available here. Primitives and its wrapped types compatibility
Introduction
How often do you think about possible changes in your API? Do you consider that something required could become optional in future? How about compatibility of such change? One of this changes is going from primitive (e. g. int
) to its wrapped type (e. g. Integer
). Let's check it out.
API - first iteration
Let's start with simple DTO class Dep
in our public API.
public class Dep {
private int f1;
public int getF1(){
return f1;
}
public void setF1(int f1){
this.f1 = f1;
}
// other fields and methods omitted
}
f1
is obligatory field that never will be null.
Let's use it in Main
class:
public class Main {
public static void main(String... args) {
Dep dep = new Dep();
dep.setF1(123);
System.out.println(dep.getF1());
}
}
compile it:
$ javac depInt/Dep.java
$ javac -cp depInt main/Main.java
and run:
$ java -cp depInt:main Main
123
It works.
API - obligatory field become optional
Now suppose our business requirements have changed. f1
is not longer obligatory and we want possibility to set it to null
.
So we provide next iteration of Dep
class where f1
field has type Integer
.
public class Dep {
private Integer f1;
public Integer getF1(){
return f1;
}
public void setF1(Integer f1){
this.f1 = f1;
}
// other fields and methods omitted
}
We compile only the new Dep
class because we do not want to change the Main
class:
$ javac depInteger/Dep.java
and run it with old Main
:
$ java -cp depInteger:main Main
Exception in thread "main" java.lang.NoSuchMethodError: Dep.setF1(I)V
at Main.main(Main.java:4)
Wow! It does not work...
Why does it not work?
We can use javap
tool to investigate Main
class.
$ javap -c main/Main.class
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: new #2 // class Dep
3: dup
4: invokespecial #3 // Method Dep."<init>":()V
7: astore_1
8: aload_1
9: bipush 123
11: invokevirtual #4 // Method Dep.setF1:(I)V
14: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
17: aload_1
18: invokevirtual #6 // Method Dep.getF1:()I
21: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
24: return
}
The most important are 11th and 18th instructions of main
method. Main
lookups for methods which use int
(I
in method signature).
Next let's compile the Main
class with Dep
which has f1
of type Integer
:
$ javac -cp depInteger main/Main.java
and use javap
on this class:
$ javap -c main/Main.class
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: new #2 // class Dep
3: dup
4: invokespecial #3 // Method Dep."<init>":()V
7: astore_1
8: aload_1
9: bipush 123
11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: invokevirtual #5 // Method Dep.setF1:(Ljava/lang/Integer;)V
17: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_1
21: invokevirtual #7 // Method Dep.getF1:()Ljava/lang/Integer;
24: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
}
Now we see the difference. The main
method:
- converts
int
toInteger
in instruction 11th, - invokes method
setF1
which takes parameter of typeInteger
(Ljava/lang/Integer;
) in instruction 14th, - invokes method
getF1
which returnsInteger
in instruction 21st.
These differences do not allow us to use the Main
class with Dep
without recompilation if we change f1
.
How about Groovy?
We have GroovyMain
class which do the same as Main
class written in Java.
class GroovyMain {
static void main(String... args) {
Dep dep = new Dep(f1: 123)
println(dep.f1)
}
}
We will compile GroovyMain
class only with Dep
which uses int
:
$ groovyc -cp lib/groovy-all-2.4.5.jar:depInt -d main main/GroovyMain.groovy
It runs great as expected with int
:
$ java -cp lib/groovy-all-2.4.5.jar:depInt:main GroovyMain
123
but with Integer
... It works the same!
$ java -cp lib/groovy-all-2.4.5.jar:depInteger:main GroovyMain
123
Groovy is immune to such change.
With CompileStatic
But what if we compile groovy with CompileStatic
annotation? This annotation instructs groovy compiler to compile class with type checking and should produce bytecode similar to javac
output.
GroovyMainCompileStatic
class is GroovyMain
class with only CompileStatic
annotation:
import groovy.transform.CompileStatic
@CompileStatic
class GroovyMainCompileStatic {
static void main(String... args) {
Dep dep = new Dep(f1: 123)
println(dep.f1)
}
}
When we compile this with Dep
with int
field:
$ groovyc -cp lib/groovy-all-2.4.5.jar:depInt -d main main/GroovyMainCompileStatic.groovy
then of course it works:
$ java -cp lib/groovy-all-2.4.5.jar:depInt:main GroovyMainCompileStatic
123
but with Dep
with Integer
field it fails like in Java:
$ java -cp lib/groovy-all-2.4.5.jar:depInteger:main GroovyMainCompileStatic
Exception in thread "main" java.lang.NoSuchMethodError: Dep.setF1(I)V
at GroovyMainCompileStatic.main(GroovyMainCompileStatic.groovy:6)
Conclusion
Change from primitive to its wrapped java type is not compatible change. Bytecode which uses dependent class assumes that there will be method which consumes or returns e. g. int
and cannot deal with the same class which provides such method with Integer
in place of int
.
Groovy is much more flexible and could handle it, but only if we do not use CompileStatic
annotation.
The source code is available here.
Scheduling tasks using Message Queue
Introduction
How to schedule your task for later execution? You often create table in database, configure job that checks if due time of any task occured and then execute it.
But there is easier way if only you have message broker with your application... You could publish/send your message and tell it that it should be delivered with specified delay.
Scheduling messages using ActiveMQ
ActiveMQ is open source message broker written in Java. It is implementation of JMS (Java Message Service).
You could start its broker with scheduling support by adding flag schedulerSupport
to broker configuration:
<beans ...>
...
<broker xmlns="http://activemq.apache.org/schema/core"
brokerName="localhost"
dataDirectory="${activemq.data}"
schedulerSupport="true">
...
</broker>
...
</beans>
Now, if you want to delay receiving message by few seconds, you could add property during message creation, e.g.:
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 8000)
Delay unit is miliseconds.
Of course queue must be persisted.
When you listen for message on the same queue, then you will see that message indeed will be received with 8 second delay.
...
Send time: Tue Dec 01 18:51:23 CET 2015
...
Message received at Tue Dec 01 18:51:31 CET 2015
...
Scheduling messages using RabbitMQ
Scheduling tasks is not only the feature of ActiveMQ. It is also available with RabbitMQ.
RabitMQ is message broker written in Erlang. It uses protocol AMQP.
First you have to install plugin rabbitmq_delayed_message_exchange
. It could be done via command:
rabbitmq-plugins enable --offline rabbitmq_delayed_message_exchange
You have to define exchange in RabbitMQ which will use features from this plugin. Queue for delayed messages should be bound to this exchange. Routing key should be set to queue name.
channel.exchangeDeclare(exchange, 'x-delayed-message', true, false, ['x-delayed-type': 'direct']);
channel.queueBind(queue, exchange, queue);
channel.queueDeclare(queue, true, false, false, null);
Of course queue must be persisted.
To test it just publish new message with property x-delay
:
channel.basicPublish(exchange,
queue,
new AMQP.BasicProperties.Builder().headers('x-delay': 8000).build(),
"Message: $currentUuid".bytes)
Message will be delayed with 8 seconds:
...
Send time: Tue Dec 01 19:04:18 CET 2015
...
Message received at Tue Dec 01 19:04:26 CET 2015
...
Conclusion
Why you create similar mechanism for handling scheduled tasks on your own, when you could use your message brokers and delayed messages to schedule future tasks?
Sources are available here.
How to recover after Hibernate’s OptimisticLockException
I've read many articles about optimistic locking and OptimisticLockException itself. Problem is that each one of them ended up getting their first exception and no word on recovery. What to do next? Repeat? If so, how? Or drop it? Is there any chance to continue? How? Even more, documentation says that if you get Hibernate exception - you're done, it's not recoverable:
An exception thrown by Hibernate means you have to rollback your database transaction and close the Session immediately (this is discussed in more detail later in the chapter). If your Session is bound to the application, you have to stop the application. Rolling back the database transaction does not put your business objects back into the state they were at the start of the transaction. This means that the database state and the business objects will be out of sync. Usually this is not a problem, because exceptions are not recoverable and you will have to start over after rollback anyway.
Here is my attempt on this: repeatable and recoverable.
Business case
Let's say we have distributed application with two web servers, connected to the same database. Applications use optimistic locking to avoid collisions. Customers buy lottery coupons, which are numbered from 1 to 100. In the same second Alice on web server 1 draws two coupons: 11 and 12. In the same moment Bob reserves two coupons on web server 2. It draws 11 and 13 for Bob and tries to write it back to database. But it fails, since Alice's commit was first. I want a web application server to draw coupons for Bob again and then - try to save again until it succeeds.
Solution
For every request Hibernate associates different Session that is flushed at the end of request processing. If you hit OptimisticLockException then this Request Session is polluted and will be rolled back. To avoid this we will create a separate Hibernate's Session especially for drawing coupons. If separate session fails - drop this session and try again in a new one. If it succeeds - merge it with a main request session. Request Session cannot be touched during draws. Take a look at the following picture:
On this picture yellow and green short-term sessions has failed with OptimisticLockException. Red session was successful and these objects are merged to a main session on the left.
Reservation entity
Key requirement here is to keep a domain you want to lock on as small as possible and not coupled directly to anything else. Best approach here is to create some Reservation
entity with few fields, let's say: couponId
and customerId
. For each Coupon
create one Reservation
row and use reserved
boolean field as a reservation status. For coupon and customer use weak identifiers (long
) instead of real entities. This way no object tree will be loaded and Reservation
stays decoupled.
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import static org.apache.commons.lang3.Validate.isTrue;
import static org.springframework.util.Assert.isNull;
@Getter
@Setter
@ToString
@Entity
public class Reservation {
@Id
private long id;
@Column("coupon_id")
private long couponId;
@Column("customer_id")
private Long customerId;
@Column("is_reserved")
private boolean reserved;
public void reserve(long reservingCustomerId) {
isTrue(reserved == false);
isNull(customerId);
reserved = true;
customerId = reservingCustomerId;
}
}
Method reserve
has some business assertions to keep it legit. You can also spot lombok's annotations that provide getters, setters and toString
methods on the fly.
Reservation Service
Reservation Service implements my solution. I've commented some steps for better reading. Please read a source code:
import lombok.extern.slf4j.Slf4j;
import org.hibernate.*;
import org.hibernate.ejb.HibernateEntityManager;
import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceContext;
import java.util.List;
@Slf4j
public class ReservationService {
@PersistenceContext
private HibernateEntityManager hibernateEntityManager;
@SuppressWarnings("uncheked")
private Iterable<Reservation> reserveOptimistic(long customerId, final int count) throws NoFreeReservationsException {
log.info("Trying to reserve {} reservations for customer {}", count, customerId);
//This is the request session that needs to stay clean
Session currentSession = hibernateEntityManager.getSession();
Iterable<Reservation> reserved = null;
do {
//This is our temporary session to work on
Session newSession = hibernateEntityManager.getSession().getSessionFactory().openSession();
newSession.setFlushMode(FlushMode.COMMIT);
Transaction transaction = newSession.beginTransaction();
List<Reservation> availableReservations = null;
try {
Query query = newSession.createQuery("from Reservation r where r.reserved = false")
.setLockMode("optimistic", LockMode.OPTIMISTIC)
.setMaxResults(count);
availableReservations = query.list();
//There is no available reservations to reserve
if (availableReservations.isEmpty()) {
throw new NoFreeReservationsException();
}
for (Reservation available : availableReservations) {
available.reserve(customerId);
newSession.save(available);
}
//Commit can throw optimistic lock exception if it fails
transaction.commit();
//Commit succeeded - this reference is used outside try-catch-finally block
reserved = availableReservations;
} catch (OptimisticLockException | StaleObjectStateException | HibernateOptimisticLockingFailureException e) {
log.info("Optimistic lock exception occurred for customer {} and count {}: {} {}", customerId, count, e.getClass(), e.getMessage());
transaction.rollback();
for (Reservation availableMsisdn : availableReservations) {
newSession.evict(availableMsisdn);
}
} finally {
newSession.close();
}
//Repeat until we reserve something
} while (reserved == null);
log.info("Successfully reserved {} reservations for customer {}", count, customerId);
//Merge reserved entities to request session
for (Reservation reservedMsisdn : reserved) {
currentSession.merge(reservedMsisdn);
}
return reserved;
}
}
This code says it all. It tries to reserve some Reservation
s until it succeeds in a do-while loop. Main Request Session is not polluted and it achieves our goal.
I hope this example helps you in similar some cases. It works as expected for a few months on our customer's production site and I recommend this solution.
What’s the cause of your problem?
Exception cause = new Exception("I'm the cause!");
SSLHandshakeException noCauseExc = new SSLHandshakeException(String.format("SSL problem: [%s]", cause.getMessage()));
noCauseExc.printStackTrace();
...and you lose stacktrace which is crucial!
There's a solution Throwable::initCause(). Check this code and have cause tailed to your exception
import javax.net.ssl.SSLHandshakeException;
/**
* Created by bartek on 04.09.15.
*/
public class Cause {
public static void main(String[] args) {
Exception cause = new Exception("I'm the cause!");
SSLHandshakeException noCauseExc = new SSLHandshakeException(String.format("SSL problem: [%s]", cause.getMessage()));
noCauseExc.printStackTrace();
SSLHandshakeException withCauseExc = new SSLHandshakeException("Another SSL problem");
withCauseExc.initCause(cause);
withCauseExc.printStackTrace();
}
}