NullPointer while using JPA EntityManager in a ThredPoolExecutor - jpa

I'm implementing a JavaEE8 application using CDI and running on an Open Liberty (v20.0.0.4). The application has a event-triggered job, which runs some code in an separate thread using the ThreadPoolExecutor like this:
#Singleton
public class MyJobExecutorService {
#PostConstruct
public void init() {
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
public void runJob(MyConfigs configs) {
thredPoolExecutor.submit(() -> new MyJobRunnable(configs).run());
}
}
The job gets data from the underlying sql database using an EntityManager, which is injected in the data access class and produced like following. My querys are written using querydsl (which should not be relevant).
public class EntityManagerProducer {
#PersistenceContext(unitName = "my-unit")
private EntityManager entityManager;
#Produces
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
}
My persistence.xml looks like this:
<persistence ...>
<persistence-unit name=my-unit">
<jta-data-source>jdbc/datasource</jta-data-source>
</persistence-unit>
</persistence>
I have no issues accessing the database from the main thred, but the job throws a NullPointerException with the following stacktrace (and no further information):
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:213)
com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:164)
com.ibm.ws.jpa.management.JPAEntityManager.getDelegate(JPAEntityManager.java:402)
com.querydsl.jpa.impl.JPAProvider.getTemplates(JPAProvider.java:61)
com.querydsl.jpa.impl.JPAQuery.<init>(JPAQuery.java:48)
com.querydsl.jpa.impl.JPAQueryFactory.query(JPAQueryFactory.java:138)
com.querydsl.jpa.impl.JPAQueryFactory.select(JPAQueryFactory.java:81)
com.querydsl.jpa.impl.JPAQueryFactory.selectFrom(JPAQueryFactory.java:111)
my.application.MyRepository.getAll(DataAccess.java:67)
sun.reflect.GeneratedMethodAccessor1888.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.MyRepository$Repository$Serializable$925348889$Proxy$_$$_WeldClientProxy.getAll(UnknownSource)
sun.reflect.GeneratedMethodAccessor1887.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.DataAccess$587668909$Proxy$_$$_WeldClientProxy.getAllData(UnknownSource)
my.application.job.MyDefaultJob.runJob(MyDefaultJob.java:50)
sun.reflect.GeneratedMethodAccessor1886.invoke(UnknownSource)
java.lang.reflect.Method.invoke(Method.java:498)
org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
my.application.job.MyJob$588111896$Proxy$_$$_WeldClientProxy.runJob(UnknownSource)
my.application.job.MyJobExecutorService$MyRunnable.run(MyJobExecutorService.java:59)
my.application.job.MyJobExecutorService.lambda$runJob$0(MyJobExecutorService.java:36)
my.application.job.MyJobExecutorService$$Lambda$280/00000000A8128A20.run(UnknownSource)
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:823)
Why am I getting this exception and how can I fix this? Activating the jpa an concurrency features in the server.xml of the application server didnt help. Thanks a lot.

Enabling the concurrent-1.0 feature alone doesn't do anything unless you are using the managed resources that it provides which capture the context of the application component (such as its java:comp name space and so forth) and makes it available when running the tasks that are submitted to it.
If you must use a ThreadPoolExecutor in order to manipulate its queue in some way beyond enforcing concurrency constraints (ManagedExecutorService can impose concurrency constraints via a configurable concurrencyPolicy), the simplest way to continue using a ThreadPoolExecutor is by supplying it with a ManagedThreadFactory,
#PostConstruct
public void init() {
ManagedThreadFactory threadFactory = InitialContext.doLookup(
"java:comp/DefaultManagedThreadFactory");
thredPoolExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
threadFactory);
}
ManagedThreadFactory captures the context that is present on the thread from which it is initially looked up. You'll need to decide if there is a better place for it than your init() method based on what context you want it to provide to your ThreadPoolExecutor tasks.
You should also be aware that any use of ThreadPoolExecutor (even in combination with a ManagedThreadFactory or ContextService) bypasses use of the Liberty global thread pool.

Related

Write/Run Junit Test class (To test actuators) without Datasource bean creation in springboot container

What we are trying to do?
Writing a Junit for Springboot actuator/Admin as below
Code snippet:
ActuatorTests.java
#SpringBootTest(properties = {
"management.endpoints.web.exposure.include=" })
#ActiveProfiles(profiles = "local")
#AutoConfigureMockMvc
public class ActuatorTests {
#Autowired
private MockMvc mockMvc;
#MockBean
JwtDecoder jwtDecoder;
#Test
public void testActuatorEndpointSuccess() throws Exception {
MockHttpServletResponse resp = mockMvc
.perform(MockMvcRequestBuilders.get("/actuator/").accept(MediaType.APPLICATION_JSON)).andReturn()
.getResponse();
assertEquals(resp.getStatus(), 200);
}
application-local.yml
This property contains Datasource, username, password and others properties
What is the issue?
During spring boot container start, it is creating Data Source by using data source properties of application-local.yml
Problem here is I can't rely on application-local.yml becoz properties changes environment to environment may not work all the time with same property values and also which is unnecessary for my Junit as the testcase is about testing the management actuator endpoint only.
What we have tried?
Ran by excluding some the JPA classes using below.
#SpringBootTest(properties = {
"management.endpoints.web.exposure.include=" })
#ActiveProfiles(profiles = "local")
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class ActuatorTests { .....}
But found the below error in the console.
Note: the error log also having chain of bean creation errors from DAO,Service, to Controller layer classes,
I have given only the tail of the log due to restrictions.
**Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available**
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:805)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1278)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 118 common frames omitted
Any help on this?
We can see similar question has been asked but no answer found in it.
Run junit without data source persistence context in spring boot
Any other solution to above actuator Test Junit is also welcome..

Run Java EE CDI task with interval

I need to run a task with interval once my application (WAR) starts, I am using WildFly 21.
The task should be initialized at startup and perform some work at some interval.
the class is below
#ApplicationScoped
#ActivateRequestContext
public class TaskRunner {
#Resource private ManagedScheduledExecutorService scheduler;
#Inject private ScheduledFuture<?> TaskRunnerScheduler;
private boolean initialized = false;
private void init(#Observes #Initialized(ApplicationScoped.class) Object init) {
if (initialized) return;
initialized = true;
try {
// Execute at startup
TaskRunner = scheduler.schedule(this::runSchedule, getSchedule());
} catch (Throwable throwable) {
}
}
private void runSchedule() {
//do some work
}
private Trigger getSchedule() {
return new Trigger() {
#Override
public Date getNextRunTime(LastExecution lastExecutionInfo, Date taskScheduledTime) {
return Date.from(
ZonedDateTime.now().withSecond(0).withNano(0).plusHours("4").toInstant());
}
#Override
public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime)
{return false;}};
}
}
When trying to deploy the application, I am getting the following error
ERROR [org.jboss.msc.service.fail] (MSC service thread 1-6) MSC000001: Failed to start service jboss.deployment.unit."task-web.war".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."task-web.war".WeldStartService: Failed to start service
at org.jboss.msc#1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1731)
at org.jboss.msc#1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1559)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type ScheduledFuture<?> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject private TaskRunner.TaskRunnerScheduler
at TaskRunner.TaskRunnerScheduler(TaskRunner.java:0)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:378)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:290)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:143)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:164)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:526)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:64)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:62)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
at org.jboss.weld.core#3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.JBossThread.run(JBossThread.java:513)
Any ideas what is the cause of this error?
It looks like you want to run every 4 hours or so. Can I suggest a bit cleaner implementation?
#Startup
#Singleton
public class MyScheduler {
#PostConstruct
private void runAtStartup() {
// whatever makes sense here
}
#Schedule(hour = "*/4", persistent = false )
private void runSomething() {
// something here
}
}
This sets up an EJB to run at startup (#Startup), saying that there is only one instance of it (#Singleton). It then runs the runSomething() method every 4 hours. You can take a look at the Schedule Javadocs as there are many other ways to run this too. You may or may not need the #PostConstruct method if it previously only existed to setup the timer.
The persistent parameter tells Wildfly to remember when the last run was and, if restarted, continue to run on that schedule. If you don't care if your method runs again on restart then leave this false.
My only warning is that this mechanism doesn't handle overlaps. If you use this and a new schedule method is run before the last one finishes (in this example, 4 hours later) it can lead to errors in at least your log and the schedule not running the way you expect it to.
From your code snippet alone, simply remove the (unused) TaskRunnerScheduler field.
I found the issue, it was a typo in the following line
#Inject private ScheduledFuture<?> TaskRunnerScheduler;
the correct one is without the inject
private ScheduledFuture<?> TaskRunnerScheduler;

Upgrading from Spring Boot 1.5 to 2.0 - cannot execute UPDATE in a read-only transaction

Updating Spring Boot 1.5 to 2.1.5
When trying to do a operation repository.save(entity) it gives the following error:
Caused by: com.impossibl.postgres.jdbc.PGSQLSimpleException: cannot execute UPDATE in a read-only transaction
We use the org.springframework.data.repositoryCrudRepository interface to perform the operations.
1) #Transactional(readOnly = false), as i understood setting Read-Only mode to false only works as a hint to the sub-layers, how can i check and change the other layers?
#Service
public class ServiceImpl
private final Repository repository;
#Autowired
public ServiceImpl(Repository repository) {
this.repository = repository;
}
#Transactional(readOnly = false)
public void operation(Entity entity){
repository.save(entity);
}
And Repository is
public interface Repository extends CrudRepository<Entity, UUID>{
#Query("select e from Entity e where lower(u.name) = lower(?1)")
Entity findByName(String name);
}
build.gradle
------------
`dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.5.RELEASE")
}
`
```runtime("org.springframework.boot:spring-boot-properties-migrator")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-jersey")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-jetty")
compile("org.springframework.boot:spring-boot-starter-mail")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.quartz-scheduler:quartz:2.3.1")
compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
compile("com.fasterxml.woodstox:woodstox-core:5.2.1")
compile("org.glassfish.jersey.media:jersey-media-multipart:2.28")
compile("net.java.dev.msv:msv-core:2013.6.1")
compile("com.impossibl.pgjdbc-ng:pgjdbc-ng:0.8.2")
compile('org.apache.commons:commons-lang3:3.9')
compile('commons-io:commons-io:2.6')
compile('org.apache.commons:commons-compress:1.18')
compile('org.apache.poi:poi-ooxml:4.1.0')
compile('org.apache.xmlbeans:xmlbeans:3.1.0')
compile('org.mitre.dsmiley.httpproxy:smiley-http-proxy-servlet:1.10')
compile('com.monitorjbl:xlsx-streamer:2.1.0')
compile('com.zaxxer:HikariCP:3.3.1')
application.properties
spring.datasource.driverClassName=com.impossibl.postgres.jdbc.PGDriver
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.idle-timeout=10000
# Set auto-commit = false, otherwise - Caused by: java.sql.SQLException:
Clobs require connection to be in manual-commit mode...
spring.datasource.hikari.auto-commit=false
logging.level.ROOT=INFO
logging.level.org.springframework.orm.jpa=DEBUG
logging.level.org.springframework.transaction=DEBUG
One important thing is that i added the Auto-Commit to false in Hikari, otherwise it would fail with an exception as it can bee seen in the comment.
Note: In some threads it was suggested to check postgres connection
show default_transaction_read_only;
default_transaction_read_only
-------------------------------
off
SELECT pg_is_in_recovery();
pg_is_in_recovery
-------------------
f
Thanks in advance.
Property readOnly is false by default, so you should never use #Transactional(readOnly = false), use #Transactional instead.
When you mark some methods or class with #Transactional Spring creates a proxy of that class to inject the logic of Transaction Manager. It uses a bean that implements interface org.springframework.transaction.PlatformTransactionManager
In your specific case a bean of org.springframework.orm.jpa.JpaTransactionManager will be created.
Spring Boot is using Hibernate as a default JPA provider, so eventually all transaction logic will affect Hibernate. E.g. readOnly = true is used in order to disable "dirty checking" mechanism that performs all UPDATE operations in Hibernate.
By default, Spring Transaction Manager creates a new Hibernate Session (new transition) when it calls a method marker with #Transactional and no Session is attached to the current thread. So all the following calls in the current thread will use the same Session (and same transaction). Unless you change the propagation property.
It all means that configs for the transaction are set when Spring calls #Transactional method the first time and those configs are used for all methods calls in the same thread. See the code example:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
#Service
public class ServiceA {
#Transactional(readOnly = true)
public void a() {
boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
System.out.println(isReadOnly);
}
}
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
#Transactional
public void b() {
serviceA.a();
}
}
serviceA.a() will print true
serviceB.b() will print false
See Spring Boot 2.0 Migration Guide about Gradle and add dependency management plugin:
Spring Boot’s Gradle plugin no longer automatically applies the dependency management plugin. Instead, Spring Boot’s plugin now reacts to the dependency management plugin being applied by importing the correct version of the spring-boot-dependencies BOM. This gives you more control over how and when dependency management is configured.
For most applications applying the dependency management plugin will be sufficient:
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management' // <-- add this to your build.gradle
Also you can remove spring.datasource.type
If you used spring.datasource.type to force the use of Hikari in a Tomcat-based application, you can now remove that override.
Notice also that minimum Hibernate version is 5.2
Also I see you added spring-boot-properties-migrator, note that it should be removed after you finish migration tweaks
Once you’re done with the migration, please make sure to remove this module from your project’s dependencies.

How to load spring application context even if Cassandra down

When using
#Configuration
#EnableCassandraRepositories(basePackages={"com.foo"})
public class CassandraConfig{
#Bean
public CassandraClusterFactoryBean cluster()
{
final CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(nodesRead);
cluster.setPort(port);
return cluster;
}
Where in the com.foo package there is a interface that extends CrudRepository.
Is there a way to make it so that at startup time an exception is not thrown if the database is down?
Ideally what occurs is that we startup and anytime you call a method on the repository, it will first attempt to connect to the database and then if the database is still down return an error saying can't connect.
The behavior I currently observe is that NoHostAvailableException is thrown and the web container does not start up.
I was able to come up with a solution. I removed the #EnableCassandraRepositories(basePackages={"com.foo"}) annotation from the repository and defined a Bean in my Config that would return my repository. Removing the EnableCassandraRepositories allowed lazy loading of the repository. This new bean in my Config allowed me to instantiate my repository using the RepositoryFactorySupport getRepository() method. I annotated this bean as lazy and made sure references to the bean were also lazy.
Assume my repository looks like the following
public interface IBarRepository extends CrudRepository<Bar, BarKey>{}
My Config file now looks like
#Configuration
public class CassandraConfig{
#Bean
#Lazy(value=true)
public IBarRepository barRepository() throws Exception
{
final RepositoryFactorySupport support = CassandraRepositoryFactory(cassandraTemplate());
return support.getRepository(IBarRepository.class);
}
#Bean
#Lazy(value=true)
public CassandraClusterFactoryBean cluster()
{
final CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(nodesRead);
cluster.setPort(port);
return cluster;
}
//More beans down here defining things like cluster, mappingContext, session, etc.

Using #EJB injection in an Application Client, both in same EAR

I've searched now for days to find some solution for my, in my opinion not too hard but obviously unsolvable problem.
I have an EAR project containing Some EJB, a web client (works fine) and now I added an Application Client Module.
As everything is in the same project, I thought a simple #EJB injection in the main class of the application client would do. I also tried a JNDI lookup.
I use eclipse and glassfish as a server and tried to run the application 1. in eclipse (there my injected bean is just null) and 2. downloaded the client-stub from the glassfish administration and tried to start it with sh appclient -client (or -jar) OmazanClient.jar (and also the other two jars hidden in the client-stub folder). There I get mostly a "ClassNotFoundExeption:Main" like
java.lang.ClassNotFoundException: Main
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.glassfish.appclient.client.acc.ACCClassLoader.findClass(ACCClassLoader.java:212)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at org.glassfish.appclient.client.acc.FacadeLaunchable.getMainClass(FacadeLaunchable.java:262)
at org.glassfish.appclient.client.acc.AppClientContainer.setClient(AppClientContainer.java:324)
at org.glassfish.appclient.client.acc.AppClientContainerBuilder.createContainer(AppClientContainerBuilder.java:185)
at org.glassfish.appclient.client.acc.AppClientContainerBuilder.newContainer(AppClientContainerBuilder.java:172)
at org.glassfish.appclient.client.AppClientFacade.createContainerForAppClientArchiveOrDir(AppClientFacade.java:492)
at org.glassfish.appclient.client.AppClientFacade.createContainer(AppClientFacade.java:454)
at org.glassfish.appclient.client.AppClientFacade.prepareACC(AppClientFacade.java:269)
at org.glassfish.appclient.client.acc.agent.AppClientContainerAgent.premain(AppClientContainerAgent.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:338)
So for the injection, my code looks like:
public class Main {
#EJB (mappedName="ejb/customerBean")
public static CustomerInterface customerBean;
#EJB (mappedName="ejb/productBean")
public static ProductInterface productBean;
public static void main(String[] args) {
try{
Main m = new Main();
m.runDialog();
}
catch (Exception e){
e.printStackTrace();
}
}
/* (non-Java-doc)
* #see java.lang.Object#Object()
*/
public Main() {
super();
}
private void runDialog() throws Exception{
System.out.println("Test");
List<ProductDTO> productList = productBean.getAllProducts();
...
My remote interface looks like this:
#Remote
public interface ProductInterface {
public int addProduct(String productName);
public void deleteProduct(int prodid);
public void updateProduct(int prodid, String newName);
List<ProductDTO> getAllProducts();
...
My implementation is this:
/**
* Session Bean implementation productInterface
* */
#Stateless(mappedName="ejb/productBean")
#LocalBean
#WebService
public class ProductBean implements ProductInterface {
#EJB ProductEAO eao;
#EJB Conversion conv;
/**
* Default constructor.
*/
public ProductBean() {
// TODO Auto-generated constructor stub
}
#Override
public int addProduct(String prodName) {
return eao.addProduct(prodName);
}
#Override
public List<ProductDTO> getAllProducts() {
List<ProductDTO> result = new ArrayList<ProductDTO>();
List<Product> allProducts = eao.allProducts();
for (Product pr : allProducts) {
ProductDTO ci = conv.fromProduct(pr);
result.add(ci);
}
return result;
}
... and so on (all methods required by the interface are implemented, just try to keep it shorter here)
and the MANIFEST.MF is just
Manifest-Version: 1.0
Main-Class: Main
I've tried a lot like JNDI lookup, giving the bean names (see example) etc. But either the interface is not found (lookup) or the bean simply null.
How ever I am also not quite sure how to run the application client. I thought glassfishs appclient is the right starting point? It shall be a console-interaction so no swing components or anything similar.
Now I'd be thankful for any suggestions what I might have missed.
Cheers :)
Found a solution. Somehow, JNDI works now. Another problem was that my db query returned an Object and not primitive value or string - this caused a buffer error.
However, I am still confused on how to export an run an application client correctly. Maybe someone has an idea?!
There is a good example here: Create and Run a JEE6 Client Application with Netbeans 6.8 and Glassfish V3 - Part 2: Enhancing and Deploying the Application. It is a few years old, but it does give a pretty good overview.