Hot questions for Using Enterprise JavaBeans in spring boot

Question:

I've gone through the Spring Boot docs but don't know if it is feasible to create a Spring Boot web application which invokes remote EJB 3.0 beans.

I don't have much experience with invoking EJBs from within Spring, but have read through Spring's Chapter 29 Enterise EJBs and it "seems" fairly straightforward.

However, is there anyway to create a Spring Boot app with an embedded container and still invoke remote EJBs? Or do I have to deploy a war to a JEE-enabled app server (ex: JBoss, Glassfish, Websphere, etc).

Are there any gotcha's or issues I have to consider when trying to invoke remote EJB 3.0 from within a Spring Boot app?


Answer:

You do not need a container that provides a full Java EE implementation in order to access remote EJBs.

You can invoke a remote EJB from a simple command line program if you want.

Just follow the instructions that you linked for remote EJBs.

Note that configuration required for different target servers (where your remote EJB is hosted) can vary widely between implementations, so you will need to find out how to do it for that specific host.

You may find it easier to get a working configuration in a command line client before trying to get Spring set up because there will be less moving parts to deal with.

Question:

I'm using Spring to handle my transactions.Actually,I saw an example in which we have a method that made find on a table using default transactionn aspect @RequiredNew with readOnly=true.

    @Override
    @Transactional(readOnly = true)
    public E findAll(E entity) {
        return repository.save(entity);
    }

My question is why not making like this and what's the difference ?

@Transactional(propagation = Propagation.NEVER)
    @Override
    public Iterable<E> findAll() {
        return repository.findAll();
    }

Answer:

The readOnly property tells both Hibernate and your database that you don't want any possible changes to be committed. This sets FlushMode.NEVER in the current Hibernate Session. Even if you call a save() method, no changes will happen in your database.

Propagation.NEVER, means that Spring will execute the operation non-transactionally, and will throw an Exception if a transaction exists. This ensures that no transaction will be created.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html

Question:

Here is a architectural problem while using Dao and Service and Controller:

Suppose that: In DAO layer, there are DAO Classes called: Dao1, Dao2, ...

In Service Layer, there are Service Classes called: Service1, Service2, ...

In Controller Layer, there are Controller Classes called: Controller1, Controller2, ...

Service1 need to inject Dao1, and Service2

Controller1 need to inject Dao2, Service1 and Controller2

Does this architecture follow the JEE principales? Is there any issue?

It is better tp say that: Service can inject only Dao, and Controlleur can inject only Service?


Answer:

As per my understanding, JEE does not mention/recommend the design patterns. JEE defines the set of APIs across different areas such as transactions, jdbc, jax-rs and so on and the implementation of these APIs is provided by different vendors. Thus JEE standards help develop an enterprise application but they do not dictate any design principles. So I guess that your question is whether this architecture follows good design patterns and if there is any issue.

Ideally as per your second question, a controller must not inject a dao class. A controller must only call services and the services should inject dao classes and call their methods. This design provides loose coupling between controller, service and dao layers. This way, if the signature of a dao class method changes, the controller layer is untouched and only service layer needs to change.

Generally speaking, most designs try to achieve loose coupling and high cohesion as much as possible.

Hope this helps!

Question:

I am currently upgrading one application from Spring Boot 1.X to 2.X. One of the tests in the application is testing Stateless remote EJB using OpenEJB under the @SpringBootTest. Since the support for SpringBeanAutowiringInterceptor has been dropped in Spring 5, I am now faced with a task to rewrite the logic and test it and here comes the problem: We are running on JDK 1.8 and openejb (4.7.4, which is used in the test to initialize jndiContext) cannot handle multi-release JARs which comes as a dependencies from upgrade to Spring Boot 2.X (for example byte-buddy and others). OpenEJB tries to load META-INF/versions/9/module-info and fails on IllegalArgumentException. I am also trying switch from OpenEJB to EJBcontainer along with glassfish as loader, but I am facing different issues (Stateless bean is not set in the jndContext - inspected in DEBUG), which I am currently trying to solve.

My question is: Is there any possibility to somehow force classloader or openejb to ignore module-info to be able to run it under JDK 1.8 with multi-release jars on classpath? Or is there a way to use EJBContainer with glassfish-embedded-all, which currently doesn't load the EJB but at least load the context without error? I need to avoid the error or use another way how to test Stateless Bean in SpringBootTest.

Note: I don't want to use Arquillian

Summary of versions:

  • JDK 1.8
  • spring-boot-starter-parent: 2.1.3.RELEASE
  • openejb-core: 4.7.4
  • glassfish-embedded-all: 5.1.0

Error using openEJB (module-info, multi-release JARs problem):

ERROR OpenEJB [] []- FATAL ERROR: Unknown error in Assembler.  Please send the following stack trace and this message to users@tomee.apache.org :
 java.lang.IllegalArgumentException
    at org.apache.xbean.asm5.ClassReader.<init>(Unknown Source)
    at org.apache.xbean.asm5.ClassReader.<init>(Unknown Source)
    at org.apache.xbean.asm5.ClassReader.<init>(Unknown Source)
    at org.apache.openejb.util.AnnotationFinder.readClassDef(AnnotationFinder.java:299)
    at org.apache.openejb.util.AnnotationFinder.find(AnnotationFinder.java:164)
    at org.apache.openejb.config.DeploymentLoader.checkAnnotations(DeploymentLoader.java:2008)
    at org.apache.openejb.config.DeploymentLoader.discoverModuleType(DeploymentLoader.java:1891)
    at org.apache.openejb.config.DeploymentsResolver.processUrls(DeploymentsResolver.java:389)
    at org.apache.openejb.config.DeploymentsResolver.loadFromClasspath(DeploymentsResolver.java:302)
    at org.apache.openejb.config.ConfigurationFactory.getModulesFromClassPath(ConfigurationFactory.java:664)

Error using glassfish (probably wrong MODULES specified?):

ERROR embedded [] []- EJB6005:No EJB modules found

Important part of test class:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
    CommonTestConfiguration.class,
    DatabaseTestConfiguration.class,
    PropositionServiceConfiguration.class,
    BeanUtils.class,
    PropositionRemoteServiceImpl.class,
    PropositionRemoteService.class})
@DirtiesContext
public class PropositionRemoteServiceImplTest {

  @Autowired
  private AdminFacade adminFacade;

  private PropositionRemoteService remoteService;

  @Before
  public void setUp() throws NamingException {
    Properties props = new Properties();
    props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
    //props.put("openejb.deployments.classpath.exclude", ".*?module-info.*?");
    Context jndiContext = new InitialContext(props);
    remoteService = (PropositionRemoteService) jndiContext.lookup("PropositionRemoteServiceImplRemote");


    //    Map<String, Object> properties = new HashMap<>();
    //        properties.put(EJBContainer.MODULES, new File("target/classes"));
    //    EJBContainer ejbContainer = EJBContainer.createEJBContainer(properties);
    //    Context ctx = ejbContainer.getContext();
    //    remoteService = (PropositionRemoteService) ctx.lookup("PropositionRemoteServiceImplRemote");
}

Project structure (simplified - large project, cannot change):

ude> root node module - pom
    adapter> - node-module
        ejb-adapter> node module
            ejb-adapter-impl> node module containing Stateless bean used in test
    test> node module
        test-unit> node module where the Test class is defined and run

UPDATE: Currently trying apache-tomee (1.7.5) instead of openejb-core sbut it uses also asm5 and the same error occurs


Answer:

Problem solved using newer version openEJB -> Apache Tomee, which uses asm6 and supports JDK 1.9, even if I am using JDK 1.8, but because of multi-release JARS as dependencies from Spring Boot 2, this support is needed. Artifact used:

    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>apache-tomee</artifactId>
        <version>8.0.0-M2</version>
        <scope>test</scope>
    </dependency>