import com.openpojo.reflection.filters.FilterNonConcrete;
import com.openpojo.validation.Validator;
import com.openpojo.validation.ValidatorBuilder;
import com.openpojo.validation.test.impl.GetterTester;
import com.openpojo.validation.test.impl.SetterTester;
public class OpenPojoTest {
public static void validateBeans(String javaPackage) {
Validator validator = ValidatorBuilder.create().with(new SetterTester()).with(new GetterTester()).build();
//exclude enums, abstracts, interfaces
validator.validateRecursively(javaPackage, new FilterNonConcrete());
@Test (1)
public void testPojoRecursiv() {
// recursive
validateBeans("my.full.java.package.with.sub.packages");
@Test (2)
public void testExludingSomeClasses() {
List<PojoClass> listOfPojoClassInDto = PojoClassFactory.getPojoClasses("my.full.java.package.with.sub.packages", null);
listOfPojoClassInDto.remove(PojoClassFactory.getPojoClass(SomeSpecialClassNotToTest.class));
validator.validate(listOfPojoClassInDto);
SLF4J helps abstract logging from implementation. Even for libraries using log4j explicitely with the concept of bridge.
Maven dependencies
<!-- for SLF4J implementing log4j2 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
</dependency>
<!-- to bridge any LOG4J1 usage to SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
Since slf4j does not accept multiple boot jars, you may have to exclude log4j from dependencies :
Exclude log4j JAR
<dependency>
<groupId>my.bad.group</groupId>
<artifactId>my-bad-artifact</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
17:53:33.372 DEBUG main .wm.utils.wmcall.WmHelper:176 + setTestMode()
17:53:33.372 DEBUG main cg.wm.utils.wmcall.WmCall:176 + WmCall()
17:53:33.372 DEBUG main cg.wm.utils.wmcall.WmCall:176 . WmCall() -> (null)
17:53:33.373 DEBUG main tils.wmcall.WmCallEclipse:176 + WmCallEclipse()
17:53:33.373 DEBUG main tils.wmcall.WmCallEclipse:176 . WmCallEclipse() -> (null)
17:53:33.373 DEBUG main .wm.utils.wmcall.WmHelper:176 . setTestMode()
17:53:33.374 DEBUG main cg.wm.utils.ConfigUtils :176 + healthCheck()
log4j2.xml example
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %-30logger{2.} %msg%n" />
</Console>
<RollingFile name="cg-wm" fileName="target/log4j2/cg-wm.log"
filePattern="target/log4j2/old/cg-wm.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="cg-utils" fileName="target/log4j2/cg-utils.log"
filePattern="target/log4j2/old/cg-utils.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="ALL.error" fileName="target/log4j2/ALL.error.log"
filePattern="target/log4j2/old/ALL.error.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="ALL.warn" fileName="target/log4j2/ALL.warn.log"
filePattern="target/log4j2/old/ALL.warn.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="ALL.info" fileName="target/log4j2/ALL.info.log"
filePattern="target/log4j2/old/ALL.info.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="ALL.debug" fileName="target/log4j2/ALL.debug.log"
filePattern="target/log4j2/old/ALL.debug.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
<RollingFile name="ALL.trace" fileName="target/log4j2/ALL.trace.log"
filePattern="target/log4j2/old/ALL.trace.%i.log" immediateFlush="true"
append="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %-5.5thread %-25.25logger:%-4line %msg%n" charset="UTF-8"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="5" />
</RollingFile>
</Appenders>
<Loggers>
<!-- additivity is true by default : so we enter in all matching loggers -->
<Root level="warn">
<AppenderRef ref="Console" level="warn" />
<AppenderRef level="error" ref="ALL.error" />
<AppenderRef level="warn" ref="ALL.warn" />
<!-- every jars will enter here, so nothing below WARN -->
</Root>
<Logger name="cg.wm">
<!-- here we are in our project, we can go down to TRACE -->
<AppenderRef level="info" ref="ALL.info" />
<AppenderRef level="debug" ref="ALL.debug" />
<AppenderRef level="trace" ref="ALL.trace" />
</Logger>
<!-- specifically for each module -->
<Logger name="cg.wm.utils" level="debug">
<AppenderRef ref="Console" level="info" />
<AppenderRef ref="cg-utils" />
</Logger>
</Loggers>
</Configuration>
Result log example
07-31_14:13:48.491 DEBUG org.a.utils.ConfigUtils - + getParameter(test)
07-31_14:13:48.491 DEBUG org.a.utils.wmcall.WmHelper - + getPackageName(true)
07-31_14:13:48.492 DEBUG g.a.utils.wmcall.WmCallEclipse - + getPackageName(true)
07-31_14:13:48.492 DEBUG g.a.utils.wmcall.WmCallEclipse - . getPackageName(true) -> DEFAULT
07-31_14:13:48.492 DEBUG org.a.utils.wmcall.WmHelper - . getPackageName(true) -> DEFAULT
07-31_14:13:48.492 DEBUG org.a.utils.ConfigUtils - + getParameter(DEFAULT, test)
07-31_14:13:48.505 DEBUG org.a.utils.ConfigUtils - . getParameter(DEFAULT, test) -> (null)
07-31_14:13:48.506 DEBUG org.a.utils.ConfigUtils - . getParameter(test) -> (null)
LOGGER declaration
import net.sf.aspect4log.Log;
import static net.sf.aspect4log.Log.Level.TRACE;
@Log (1)
public class FooDao {
public void tooLowLevelFunction(){ (2)
//[...]
@Log(enterLevel = Level.TRACE, exitLevel = Level.TRACE) (3)
public void delete(String foo) {
//[...]
@Log(argumentsTemplate = "[...skipped...]", resultTemplate = "[...skipped...]") (4)
public void find(String bigXML) {
//[...]
@Log(on = { @Exceptions(exceptions = { CgException.class }, level = Level.INFO) }) (5)
public void saveOrUpdate(String foo) {
//[...]
For runtime, have log4j & aspect4log configuration files in the classpath, examples : link:log4j2.xml & link:aspect4log.xml.
Dependencies
<dependencies>
<!-- for @Log -->
<dependency>
<groupId>net.sf.aspect4log</groupId>
<artifactId>aspect4log</artifactId>
<version>1.0.7</version>
</dependency>
<!-- AspectJ for instrumentation -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<showWeaveInfo>false</showWeaveInfo>
<Xlint>adviceDidNotMatch=ignore,noGuardForLazyTjp=ignore</Xlint>
<aspectLibraries>
<aspectLibrary>
<groupId>net.sf.aspect4log</groupId>
<artifactId>aspect4log</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
</plugin>
</plugins>
@Loggable(skipArgs = true, skipResult = true, name = "PERFORMANCES")
public static void topLevelJarFunction(IData pipeline) throws ServiceException {
//[...]
Running cg.msg.tracker.ui.MainFrameIT
11:23:37.814 [main] DEBUG TEST - Running aboutTest...
11:23:38.503 [main] DEBUG TEST - ...OK in 0.689S
11:25:17.561 [main] DEBUG TEST - Running updateLAFTryNextTest...
11:25:20.865 [main] DEBUG TEST - ...OK in 3.304S
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 103.443 sec - in cg.msg.tracker.ui.MainFrameIT
And here is how you do it.
Inner Class in your test class
* The Class LogTestName.
public static class LogTestRule extends TestWatcher {
Instant startingDate = Instant.now();
@Override
protected void failed(Throwable e, Description description) {
LOGGER.debug("...KO [{}]", e.getMessage());
@Override
protected void starting(Description description) {
LOGGER.debug("Running {}...", description.getMethodName());
startingDate = Instant.now();
@Override
protected void succeeded(Description description) {
LOGGER.debug("...OK in {}", Duration.between(startingDate, Instant.now()).toString().substring(2));
Declare it’s usage in the class with @Rule
@Rule
public LogTestRule logTestRule = new LogTestRule());
16:48:35.176 [main] DEBUG TEST - Running buttonsTest...
[WARNING] buttonsTest(cg.msg.tracker.ui.ConnectionIT): Run 1 failed [Condition with alias 'broker radio button should be selected' didn't complete within 30 seconds because condition with lambda expression in cg.msg.tracker.ui.utils.ParentAssertJTestCase that uses org.assertj.swing.fixture.JRadioButtonFixture was not fulfilled.]
16:49:21.574 [main] DEBUG TEST - ...OK in 46.394S
16:49:21.665 [main] DEBUG TEST - Running connectionInfoZoneTextTest...
16:49:55.874 [main] DEBUG TEST - ...OK in 0.714S
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 85.826 sec - in cg.msg.tracker.ui.ConnectionIT
And here is how you do it.
Inner Class in your test class
* The Class RetryRule.
public static class RetryRule implements TestRule {
private final static int TRY_COUNT = 3;
@Override
public Statement apply(Statement base, Description description) {
return statement(base, description);
private Statement statement(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Throwable caughtThrowable = null;
// implement retry logic here
for (int i = 0; i < TRY_COUNT; i++) {
try {
base.evaluate();
return;
} catch (Throwable t) {
caughtThrowable = t;
// [WARNING] for a colorful Jenkins build
System.out.println("[WARNING] " + description.getDisplayName() + ": Run " + (i + 1)
+ " failed [" + t.getMessage() + "]");
LOGGER.warn(CgException.prettyPrint(t));
commonAfterClass();
commonBeforeClass();
// [ERROR] for a colorful Jenkins build
System.out.println("[ERROR] " + description.getDisplayName() + ": Giving up after " + TRY_COUNT
+ " failures.");
throw caughtThrowable;
Double rules usage
@Rule
public RuleChain chain = RuleChain.outerRule(new LogTestName()).around(new RetryRule());
@Test(expected = IllegalArgumentException.class)
public void testFromStringUnknown() {
CgPackage.fromString("Unknown");
Wait until a background task is done
Awaitility.await("Broker radio button should be visible").until(() -> mCEditor.getBrokerRadioButton().isShowing());
Best package organization is by fonctionnality first, and then technically when many classes of the same type
Always put classes in subpackage of the project
If a java project is bar-a-b, all packages are mycorp.bar.a.b.*
Don’t use different packages for a few classes, regroup them (if below or equal 3 classes by package)
Don’t put in the class name what is already in the package name, except for too generic file name
Some naming conventions
http://stackoverflow.com/questions/3226282/are-there-best-practices-for-java-package-organisation
http://www.javapractices.com/topic/TopicAction.do?Id=205
Some widely used examples
http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/overview-tree.html
https://commons.apache.org/proper/commons-lang/apidocs/overview-tree.html
Before Java 7, you had to close() streams and other closable objects in a try/catch/finally. Now Java handles everything if you use the right pattern :
try-with-resource
try (
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dstDirectory + "/" + fileName + ".zip"));
FileInputStream in = new FileInputStream(foundFile.getAbsolutePath())
ZipEntry ze = new ZipEntry(fileName);
zos.putNextEntry(ze);
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
if (delete)
foundFile.delete();
} catch (IOException e) {
LOGGER.error("Unable to zip or delete the file=" + srcDirectory + "/" + fileName + ", dest=" + dstDirectory, e);
throw e;
When a Map is static (and then accessed by multiple threads), declare it Map and instantiate it ConcurrentHashMap :
Thread-safe Map
Map<a,b> myMap == new ConcurrentHashMap<>();
Idem for a Set but this is a bit tricky :
Thread-safe Set
Set<String>
mySet = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
For objects used by static functions, try to initialize them only once and do it in thread safe mode.
Init on demand pattern
public class Something {
private Something() {}
private static class LazyHolder {
private static final Something INSTANCE = new Something();
public static Something getInstance() {
return LazyHolder.INSTANCE;
* @param input the input
* @return the package
* @throws IllegalArgumentException the illegal argument exception
public static CgPackage fromString(String input) throws IllegalArgumentException {
for (CgPackage p : CgPackage.values()) {
if (p.str().equals(input)) {
return p;
throw new IllegalArgumentException("Unknown package=" + input);
* Custom, short-named toString().
* Don't use defaults name() or toString(), they'll give the strict enum name
* @return the string
public String str() {
return this.str;