OCE EJBD 6 (1z0-895) Experiences

Today, I would like to share my experiences regarding the certified EJB exam, as I found little information on this topic while preparing for the certification.

Readings

In order to reinforce my knowledge, I’ve started with Enterprise JavaBeans 3.1. I think this book is great, it contains clear explanations, code snippets to support theory, common pitfalls (even testing EJBs) and so on. This book is not too hard to read; one can finish it within a week (even earlier, if you are familiar with the EJB related concepts – and have enough time). Nevertheless, the content of this book (in my opinion) is not enough to pass the exam. Well, it may be enough to pass, but in order to get the big picture, it is recommendable to read the whole EJB 3.1 specification (it’s right here). Now, believe me when I say that this whitepaper is boring as hell. Especially on the evenings, after a working, day, well, it seemed a challenge to me.

Someone on a forum I don’t recall, recommended this other book, Head first EJB. I personally think it’s a real bad idea to read that one, as it covers EJB 2.x which (thank God) looks nothing like EJB 3.x. It’s a waste of time, you can safely skip that.

Mock tests

Usually I am not in favor of buying testing frameworks; I can always dig up some mock tests to practice with (this was the case for both OCPJP and OCMJEA). I don’t really like to pay for something that’s right there on the internet (of course you have to be selective; not everything out there has any added value).

However, for this exam there are no free mock tests available. At all. Not a single one. You can find one or two pdf files with like 5-10 questions (usually of really poor quality) with a remark on the bottom that you can buy the complete dump for just seven million bucks. I don’t know whether the full versions are that untrustworthy too, I did not take the risk of buying them.

After two or three weeks of pointless chase after free smple questions, I’ve changed my mind and bought this software . Of course I checked out the trial version first, which just convinced me. The good news is that the full version costs only ~20$ – which is pretty cheap, I guess. It’s got more than 300 quality questions – grouped into categories like easy, though and “real brainer”. One or two of these questions even showed up at the real exam.

I don’t say that it’s a must to buy this or a similar testing tool, but…, well you should.. The EJB related topics are so huge, there are so many things to remember (annotations, xml tags, packaging etc.); it’s definitely worthy to do some practicing before sitting for the exam.

I personally failed the practice and the first mock test, so I am glad I made this investment. Questions can be tricky sometimes, but you will get used to it after seeing 20-30 of them. Anyways, they are tricky on the exam too.

The exam

was not too hard having answered all the 300+ mock questions. Nothing new showed up, I could answer (almost) all the question types with confidence.

Summary

In order to pass this exam you have to read (and memorize) a lot. It takes practice (both coding and answering questions) to score well, as the material is enormously big.

It took me 1.5 months to prepare (was only learning after work and on the weekends) but my previous EJB experience (of several years) helped me move a bit faster.

 

Spring injection with Collections

Today I would like to talk about Spring dependency injection when Collections are involved; as Spring treats these data structures in a rather strange way when used as beans.

We, as always, have to distinguish between two cases:

  • constructor and
  • field injection

(the examples below are not meant to represent clever architectural designs. The idea is to prove a point.)

1. Constructor Injection

Let’s suppose we have want to design a file system crawler to detect different types of malicious software signatures. We want to distinguish between different kinds of malicious software, and also want all the infected files to be available to all of our crawlers. Let’s also suppose that we are provided with an interface we cannot modify, and looks like:

public interface Crawler {
    public void crawl();
}

In order to share the list of infected files we are going to use Spring’s constructor injection functionality. First, we create two implementations of the interface above:

public class VirusCrawler implements Crawler {

	private List<String> infectedFiles;

	public VirusCrawler(List<String> infectedFiles) {
		this.infectedFiles = infectedFiles;

	}

	@Override
	public void crawl() {
            //...
	}

and also

public class TrojanCrawler implements Crawler {

	private List<String> infectedFiles;

	public TojanCrawler(List<String> infectedFiles) {
		this.infectedFiles = infectedFiles;

	}

	@Override
	public void crawl() {
            //...
	}
}

Ok now, let’s now put together a configuration for the crawlers; it’s something like:

@Configuration
public class CrawlerConfig {

	@Bean
	public List<String> infectedFiles() {
		return new CopyOnWriteArrayList<String>();
	}

	@Bean
	public Crawler virusCrawler(List<String> infectedFiles) {
		return new VirusCrawler(infectedFiles);
	}

	@Bean
	public Crawler trojanCrawler(List<String> infectedFiles) {
		return new TrojanCrawler(infectedFiles);
	}
}

Surprisingly enough, if you tried to run the code above (provided that you have an extra class that makes Spring start up and read the config above), you would face an exception like:

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'virusCrawler' defined in class blog.di.CrawlerConfig:
Unsatisfied dependency expressed through constructor argument with index 0 of type [java.util.List]: :
No qualifying bean of type [java.lang.String] found for dependency [collection of java.lang.String]:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {};

What now? Spring is trying to inject a list of all beans that are of type String? Cut short: yes it does. Had we had such beans, the code above would have started flawlessly – just try it if you feel like (note that it would have meant broken semantics).

How do we fix this without hacking our business logic? The answer is the miraculous expression language (EL) together with the @Value annotation. Let’s modify our configuration accordingly; we end up with something like this:

@Configuration
public class CrawlerConfig {

	public static final String INFECTED_FILES_LIST = "INFECTED_FILES";

	@Bean(name=INFECTED_FILES_LIST)
	public List<String> infectedFiles() {
		return new CopyOnWriteArrayList<String>();
	}

	@Bean
	public Crawler virusCrawler(@Value("#{" + INFECTED_FILES_LIST + "}")List<String> infectedFiles) {
		return new VirusCrawler(infectedFiles);
	}

	@Bean
	public Crawler trojanCrawler(@Value("#{" + INFECTED_FILES_LIST + "}")List<String> infectedFiles) {
		return new TojanCrawler(infectedFiles);
	}
}

Cool! We’ve just made Spring realize we want our specific List<> injected into our beans.

But wait a minute! This means that if our goal was to inject a list of all our beans which implement the interface Crawler, then we could have achieved that with as few as four lines of code! 

	@Bean
	public CrawlerAggregator aggregator(List<Crawler> crawlers) {
		return new CrawlerAggregator(crawlers);
	}

And I also counted the annotation as a separate line; we didn’t need to inject all the Crawlers one by one and create the list by adding those instances ourselves; we delegated this task to Spring.

2. Field Injection

This one is a bit easier. Let’s suppose we have a bean like this:

public class AwesomeCrawlerBean implements Crawler{
 
    @Autowired
    private List<String> infectedFiles;
 
    public void crawl() {
        //...
        infectedFiles.add(fileName);
        //...
    }
}

No big surprise, the code above throws an exception very similar to the one mentioned above. However,in this case we have two different ways to sort this error out:

  • we either use the expression language as in the previous case
  • or we make use of the @Resource annotation

In the first case, we end up with a class like this – pretty similar to the one described above:

public class AwesomeCrawlerBean implements Crawler{
 
    @Value("#{" + CrawlerConfig.INFECTED_FILES_LIST + "}")
    private List<String> infectedFiles;
 
    public void crawl() {
        //...
        infectedFiles.add(fileName);
        //...
    }
}

While in the second case we just replace the @Autowired annotation with a named @Resource:

public class AwesomeCrawlerBean implements Crawler{
 
    @Resource(name=CrawlerConfig.INFECTED_FILES_LIST)
    private List<String> infectedFiles;
 
    public void crawl() {
        //...
        infectedFiles.add(fileName);
        //...
    }
}

which is perhaps a little bit cleaner and easier to get.

Conclusions

It is not possible to inject Collections with Spring using the traditional ways. Spring will treat collections of type X as a collection of all Spring-managed beans of type X, and not as an empty collection.

In order to clearly state that we want a new, empty Spring-managed collection, we can use either the ExpressionLanguage with the @Value annotation, or (in case of field injection) the @Resource annotation.