Difference between javax.inject.Singleton and javax.ejb.Singleton
Solution 1
I found a plausible explanation here:
By default,
javax.ejb.Singleton
session beans are transactional (section 13.3.7 of the EJB 3.1 specification) and require acquisition of an exclusive lock for every business method invocation (sections 4.8.5.4 and 4.8.5.5).In contrast, a
javax.inject.Singleton
is not transactional and does not support container-managed concurrency (the major consequence being that no locking scheme is implemented by the container). [...]If you don't need EJB features, stick with
@ApplicationScoped
(javax.inject.Singleton
is not defined by CDI, and its semantics are therefore not governed by that specification).
To reduce future confusion, I use this small unit test (first level package name needs to be replaced):
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.junit.Test;
public class SingletonTest {
/** requires com.tngtech.archunit:archunit-junit:0.4.0 */
@Test
public void detectWrongSingletonAnnotation() {
final ClassFileImporter importer = new ClassFileImporter();
final JavaClasses classes = importer.importPackages("first_level_package");
noClasses().should().beAnnotatedWith("javax.inject.Singleton")
.as("Please use javax.ejb.Singleton instead of javax.inject.Singleton.")
.check(classes);
}
}
Solution 2
Since accepted answer didn't solve my problem I post my own answer. It won't be as good as article by Adam Bien but definitely will be more practical:
Consider following code:
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class DatabaseConnection {
@PostConstruct
public void init() {
System.out.println("init");
}
public ChampionComp getFirstRecord() {
return new ChampionComp("Ashe", "Teemo", "Warwick",
"Blitzcrank", "Syndra", "Anivia", "Brand", "Rammus", "Xin Zhao", "Irelia");
}
}
And this REST service:
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
@Path("/champions")
public class ChampionsAPI {
@Inject
private DatabaseConnection db;
@GET
@Produces("text/plain")
public String getClichedMessage() {
ChampionComp comp = db.getFirstRecord();
return comp.toString();
}
}
Using javax.ejb.Singleton
this code works just fine. The DatabaseConnection
instance is created once and injected to REST service.
However when replacing ejb
in import with inject
you would receive NPE in ChampionsAPI class while accessing db field - that's because your Singleton was not created (for some reason, maybe because one need to make use of interfaces while using javax.inject.Singleton
? ).
Hakan Kiyar
Updated on July 17, 2022Comments
-
Hakan Kiyar almost 2 years
im little confused. What is the exact difference between
javax.inject.Singleton
andjavax.ejb.Singleton
?