Dec 19, 2008
Risk of inheritance
Imagine situation when you want to add some behavior to class and decided to override its public methods in the child class. The following hidden issues are waiting for you:
* You don't know how this method is used and how it will be used in future in code of the parent class. Your changes may cause unpredictable behavior.
* You want to control some access points of the parent class, but in future some more points can be added and your code will fail in unpredictable time interval.
* Overridden methods will be removed in future, deprecated or change their access level.
* Some other issues depending of concrete scenario.
To avoid most of these issues use composition instead of inheritance. Create new class and declare needed behavior by implementing the same set of interfaces such a basic class. May be you need only some of them, so you can localize your needs and have easier implementation saving time for support. Then implement some methods and delegate all other to the instance of basic class.
Composition has its own disadvantages when basic class is too large or creation of the instances is too complicated, then you need to duplicate a lot of code or logic. IDE or other automation tools can help you with generation of such kind of code.
But what to do if basic class doesn't implement any interfaces and declared abstract? In this case you have to protect yourself from as many issues as possible. Create unit tests to control basic class methods and validate if all of them are known by you. These tests will notify you if basic class was changed so you need to look at new implementation and may be make changes in code or tests. To access information about declared methods use reflection API or some open source libraries that simplify access to this information. But think before if you really need inheritance in this case (if class was not designed for inheritance) and try to avoid it if possible. Develop with pleasure!
Crisis in action
public interface I {
int b = 5;
void a();
}
The question was if this declaration is correct. A received the following answer: "No. You need to change it to be correct." Here is what he wrote:
public interface I {
int b = 5;
private void a();
}
The explanation was great: "Instead this method will have visibility only in the package". The next question was about difference between abstract class and interface. The answer makes me smile: "The advantage of abstract class is that I can declare method in it and don't think about it anymore". Imagine how hard is to think about method in all other cases. :) "And why do you ask all these stupid questions? All this is so simple and doesn't matter" - he continued. After that phrase interview was finished.
So, do you want your code to be developed by such guys? If no be aware of crisis. And develop with pleasure...
Sep 13, 2008
Generics commons collections
Everybody of you who have large experience with Java thanks Apache for their commons project. This project includes a lot of libraries to extend or simplify work with JDK. One of these libraries is commons-collections.
It was very helpful when you needed to work with specific kinds of collections like multi map, lazy collections, bidirectional map, etc. Also it had a great number of iterators, comparators and utilities to avoid writing unnecessary code in your application. It allowed us to transform one collection to another, filter collection elements and many other things very easy. It introduced completely new types of collections like buffer (collection that allows objects to be removed in some well-defined order), bag (collection that counts the number of times an object appears in the collection), bidirectional map (map that allows bidirectional lookup between key and values) and created a great number of custom implementations of existing collections types.
But why I always use past sentences? Because from the beginning of Java 5 usage this library is not more so helpful. One of the main features introduced in Java 5 was generics. And of course the most useful place for generics to be applied is collections framework. I hoped that it takes not more than year to refactor existing library and add support of generics by commons-collections developers. But it didn't happen. :( But don't worry! There are some solutions of this issue. First one is to use generics version of commons-collections developed in parallel with main Apache version. At this moment they have functionality synchronized with version 3.1. Another option is to use google-collections instead. This project was started as free time development of one developer in Google for internal usage and now it contains a lot of features in comparison to commons-collections. It is driven by community, so only really needed things are included. To start work with this library or to get your own opinion take a look at the video presentation. Develop with pleasure!
Jul 20, 2008
Acceptance Test Driven Development training in Kiev
Jul 19, 2008
Advanced EasyMock techniques
Imagine that you have following document processing code:
public class DocumentService {
private DocumentProcessor processor;
public Document getDocument(long id) {
Document doc = //code to retrive document
processor.process(doc);
return doc;
}
public void setProcessor(DocumentProcessor processor) {
this.processor = processor;
}
}
public interface DocumentProcessor {
void process(Document document);
}
public class Document {
private String text;
private long wordsCount;
public Document(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public long getWordsCount() {
return wordsCount;
}
public void setWordsCount(long wordsCount) {
this.wordsCount = wordsCount;
}
}
In your tests you want to check if changes made by processor really change returned document. To check this you want to set 'wordsCount' variable value to 5. You may create your own processor to do this:
public class DocumentServiceTest {
private DocumentService documentService = new DocumentService();
private DocumentProcessor processor = new DocumentProcessor() {
public void process(Document document) {
document.setWordsCount(5);
}
};
@Test
public void testGetDocument() {
documentService.setProcessor(processor);
Document document = documentService.getDocument(3);
Assert.assertEquals(5, document.getWordsCount());
}
}
But also you can use EasyMock (in my example I use Unitils to easy manage mocks):
@RunWith(UnitilsJUnit4TestClassRunner.class)
public class DocumentServiceTest {
private DocumentService documentService = new DocumentService();
@RegularMock
private DocumentProcessor processor;
@Test
public void testGetDocument() {
expectDocumentProcessed();
documentService.setProcessor(processor);
Document document = documentService.getDocument(3);
Assert.assertEquals(5, document.getWordsCount());
}
private void expectDocumentProcessed() {
processor.process(isA(Document.class));
expectLastCall().andAnswer(new IAnswer<Object>() {
public Object answer() throws Throwable {
((Document) getCurrentArguments()[0]).setWordsCount(5);
return null;
}
});
replay(processor);
}
}
Why this is more powerful solution? Because you can change behavior of the processor in runtime and reuse the same mock in different tests with different behavior. Some times your dependencies are not so simple as document processor in my example and it is not so easy to extend or implements their methods (for example interface has 10 methods and you need only one of them). There is one more side effect of this usage - you have access to the parameters passed to the methods. You can save the parameter instance to use it in asserts or for other dependencies behavior mocking.
In 2.4 version of EasyMock 'capture' option was introduced to simplify work with method parameters. Document class from previous example doesn't have custom 'equals' method, so you can't use 'eq' method of EasyMock to check parameter of 'process' method. You can implement your own argument matcher (see IArgumentMatcher in the EasyMock guide) or use Unitils reflection comparison 'refEq', but another good option for you is to use new 'capture' option:
Capture<Document> capture = new Capture<Document>();
processor.process(and(isA(Document.class), capture(capture)));
replay(processor);
Document captured = capture.getValue();
These two techniques must be in your arsenal to use full power of EasyMock library and make your tests better. Develop with pleasure!
Jul 16, 2008
Design for scalability
Jul 14, 2008
Make your tests excellent with Unitils
Unitils started as a discussion group on unit testing. The result of these discussions is the list of guidelines that will be useful without Unitils itself. Then some people decide to build framework that will contains all in one, but be flexible enough to use it in different applications. So Unitils was born. To help developers with mapping guidelines to the framework there are tutorial and cookbook both published on the Unitils web site.
Unitils supports JUnit3, JUnit4 and TestNG and contains following modules:
- Spring module (for loading application contexts and retrieving and injecting Spring beans)
- Hibernate module (Hibernate configuration support and automatic database mapping checking)
- DbUnit module (test data management using DbUnit)
- Database module (unit-test database maintenance and connection pooling)
- EasyMock module (for creating mocks and lenient reflection argument matching)
- Inject module (for injecting (mock) objects into other objects)
Unitils configuration is very flexible and very small (if you are satisfied with default behavior). You can select any modules for your application and don't use others. Unitils work is based on annotations, so you will not need additional configuration files like except general settings file. Also Unitils provide to developers very useful assertion utilities, that based on reflection and support different modes for asserts.
Unitils has modular architecture so you can easy write your own modules to extend existing functionality. It is open source project so your modules may be included in future releases. General Maven repository contains last version of the framework so those of you who use Maven will not need manually install it. One important part is missed in Unitils - mocks for Java 'native' technologies like Servlets, JSP, JNDI and etc. I use a part of Spring framework (spring-test) for this purpose and it makes job very well.
From June 25, 2008 Unitils 1.1 became available. This release includes support of JPA, Spring transactions and complex database scripts structure. Also many integration bugs was fixed for database module.
I don't want to include examples for Unitils usage, you can find them in the tutorial or cookbook with detailed descriptions. Also there is useful video presentation with concrete samples. Make your tests better and your application code will be better. Develop with pleasure!
Jul 12, 2008
Evil 'System.currentTimeMillis()' and 'new Date()'
public class Clock {
private static long time;
private Clock() {
}
public static Date getCurrentDate() {
return new Date(getTimeMillis());
}
public static long getTimeMillis() {
return (time == 0 ? System.currentTimeMillis() : time);
}
public static void setTimeMillis(long millis) {
Clock.time = millis;
}
public static void resetTime() {
Clock.time = 0;
}
}
This class encapsulate all work with date creation and can be easy stubbed by setting internal time for particular usage. After test invocation it should be reset to disable stub behavior (DON'T FORGET TO DO IT). For some projects I extend this class with methods to retrieve shifted data to represent data in the future or in the past. If you need more complex logic (for example you will invoke date creation some times in the tested logic) then you may change 'time' static variable with 'DateTimeStrategy' class instance:
public interface DateTimeStrategy {
long getTimeMillis();
}
Then you will have more control on the data creation in your tests by implementing your own strategies. This approach not only helps me with testing but also encapsulate logic for dates creation in one place but makes my code clearer. I hate Java native implementation of work with dates and hope that in future it will be changed with something like Joda Time. I hope this approach will make your tests better. Develop with pleasure!
Be careful with your 'hashCode()'!
- Whenever it is invoked on the same object more than once during
an execution of a Java application, the hashCode method
must consistently return the same integer, provided no information
used in equals comparisons on the object is modified.
This integer need not remain consistent from one execution of an
application to another execution of the same application.
- If two objects are equal according to the equals(Object)
method, then calling the hashCode method on each of
the two objects must produce the same integer result.
- It is not required that if two objects are unequal
according to the equals(Object) method, then calling the
hashCode method on each of the two objects must produce
distinct integer results. However, the programmer should be aware
that producing distinct integer results for unequal objects may
improve the performance of hashtables.
From this contract you can draw a conclusion that 'hashCode()' implementation should use only immutable fields of the object. Why? Lets create user domain object:
public class User {
private Long id;
private String name;
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object obj) {
return (this == obj) ||
(obj instanceof User && equals((User) obj));
}
public boolean equals(User that) {
EqualsBuilder builder = new EqualsBuilder()
.append(id, that.id)
.append(name, that.name);
return builder.isEquals();
}
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder()
.append(id)
.append(name);
return builder.toHashCode();
}
}
I have used commons-lang to generate 'equals()' and 'hashCode()' but it doesn't matter. Now lets test if our 'hashCode()' is correct by running JUnit test:
public class UserTest {
@Test
public void testMutableName() {
Setusers = new HashSet ();
User user = new User("user");
user.setId(5L);
users.add(user);
user.setName("user2");
Assert.assertTrue(users.contains(user));
}
}
This test will fail because hash code of the user object was changed while user object itself was saved in the collection that uses it to save objects more efficiently.
Try to include in the 'hashCode()' only immutable fields, because you can have hidden issues not only with your own code but also with frameworks like Hibernate. If you don't have immutable fields, then be very careful and take described issues into account (recreate objects instead of changing them, don't use long live collections, return constant from 'hashCode()' or 'ID' field value). I hope this article will save you time for debugging. Develop with pleasure!
Jul 11, 2008
Effective Java (2nd Edition)
May 2008 brings us second edition of the Java bible "Effective Java" from Joshua Bloch. First edition takes first positions in many 'must read' lists for Java developers. This edition additionally includes features from Java 5 and 6. You can order it at Amazon.
FreeMarker integration with Intellij IDEA
One of the best approaches is to use live templates - very powerful feature of the IDEA. Originally I have found basic templates with full explanation here. Then I refactor all templates to work with square brackets and add some new for Spring integration:
<template name="fm.spring.bind" value="[@spring.bind '$MODEL_KEY$' /]"
description="Sping bind function for the freemarker template"
toReformat="false" toShortenFQNames="true">
<variable name="MODEL_KEY" expression=""
defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_CODE" value="false" />
<option name="JAVA_COMMENT" value="false" />
<option name="JAVA_STRING" value="false" />
<option name="XML" value="false" />
<option name="HTML" value="true" />
<option name="JSP" value="false" />
<option name="COMPLETION" value="false" />
<option name="OTHER" value="false" />
</context>
</template>
<template name="fm.spring.expr" value="${spring.status.expression}"
description="Spring binded name for the freemarker template"
toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="false" />
<option name="JAVA_COMMENT" value="false" />
<option name="JAVA_STRING" value="false" />
<option name="XML" value="false" />
<option name="HTML" value="true" />
<option name="JSP" value="false" />
<option name="COMPLETION" value="false" />
<option name="OTHER" value="false" />
</context>
</template>
<template name="fm.spring.url"
value="[@spring.url relativeUrl=$RELATIVE_URL$ /]"
shortcut="SPACE"
description="Insert URL to another page of the application"
toReformat="false" toShortenFQNames="true">
<variable name="RELATIVE_URL" expression=""
defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_CODE" value="false" />
<option name="JAVA_COMMENT" value="false" />
<option name="JAVA_STRING" value="false" />
<option name="XML" value="false" />
<option name="HTML" value="true" />
<option name="JSP" value="false" />
<option name="COMPLETION" value="false" />
<option name="OTHER" value="true" />
</context>
</template>
<template name="fm.spring.val" value="${spring.status.value}"
description="Spring binded value for the freemarker template"
toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="false" />
<option name="JAVA_COMMENT" value="false" />
<option name="JAVA_STRING" value="false" />
<option name="XML" value="false" />
<option name="HTML" value="true" />
<option name="JSP" value="false" />
<option name="COMPLETION" value="false" />
<option name="OTHER" value="false" />
</context>
</template>
These templates help me every day and save time to manual typing. May be it will be starting point of using live templates for some of us. Develop with pleasure!
Select implementation of Spring bean in runtime
I have found very useful to have such option in my applications and implemented special factory bean for this purpose:
public class SelectImplementationFactoryBean implements FactoryBean {
private String key;
private Map<String, Object> implementations;
public Object getObject() {
Object impl = implementations.get(key);
if (impl == null) {
throw new IllegalStateException("There is no implementation for key = "
+ key);
}
return impl;
}
public Class getObjectType() {
return getObject().getClass();
}
public boolean isSingleton() {
return false;
}
@Required
public void setKey(String key) {
this.key = key;
}
@Required
public void setImplementations(Map<String, Object> implementations) {
this.implementations = implementations;
}
}
Simple enough but very powerful. I will demonstrate how to use it to control database properties for integration with Hibernate:
<bean id="hibernateProperties" class="com.example.SelectImplementationFactoryBean">
<property name="key" value="${database.dialect}"/>
<property name="implementations">
<map>
<entry key="postgre">
<util:map map-class="java.util.Properties">
<entry key="hibernate.hbm2ddl.auto" value="validate"/>
<entry key="hibernate.show_sql" value="true"/>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect"/>
<entry key="hibernate.default_schema" value="test"/>
<entry key="hibernate.cache.use_second_level_cache" value="false"/>
<entry key="hibernate.cache.provider_class"
value="org.hibernate.cache.NoCacheProvider"/>
</util:map>
</entry>
<entry key="hsqldb">
<util:map map-class="java.util.Properties">
<entry key="hibernate.hbm2ddl.auto" value="validate"/>
<entry key="hibernate.show_sql" value="true"/>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
<entry key="hibernate.cache.use_second_level_cache" value="false"/>
<entry key="hibernate.cache.provider_class"
value="org.hibernate.cache.NoCacheProvider"/>
</util:map>
</entry>
</map>
</property>
</bean>
Now to switch your tests to another database you should change value of the property database.dialect between postgre and hsqldb (it can be configuration properties file or system property). I hope it will save your time. Develop with pleasure!
Jul 10, 2008
Access SVN version and build date from maven
To do this check buildnumber-maven-plugin. This plugin is used to build extended build version. To access SVN version and build timestamp (not formatted date) you need to add following plugin configuration to maven pom.xml:
<plugins>
....
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<configuration>
<buildNumberPropertyName>sources.version</buildNumberPropertyName>
<timestampPropertyName>build.timestamp</timestampPropertyName>
</configuration>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
These variables may be used to build project version, to label project artifacts or just to provide this information to end user like in following example:
- Add file version.properties to you maven module resources:
application.sources.version=${sources.version}
application.build.date=${build.timestamp}
- Add filtering section for this file to the maven pom.xml:
<resources>
....
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
Now you have more control on application version. Develop with pleasure!