Ananth created APEXCORE-452:
-------------------------------
Summary: Class Not found errors encountered for Apps with JSR 303
annotations
Key: APEXCORE-452
URL: https://issues.apache.org/jira/browse/APEXCORE-452
Project: Apache Apex Core
Issue Type: Bug
Affects Versions: 3.3.0
Environment: Cent OS 6.6 + CDH 5.7 + Apex 3.3.0 + malhar 3.3.1
Reporter: Ananth
Apps that have Validation annotations seem to be being evaluated by the bval
jar inside the engine instead of the application supplied validators. This is
causing ClassNotFoundErrors.
An App that is using Apex + Spring 4.1.9 + Spring Data + Hibernate + JPA was
used to reproduce this issue
There are annotations in the Spring JPA layer that is causing the launching of
an app to crash consistently.
The workaround seems to be adding jars that do not interfere with the Apex
engine jars. In the application above, javax.persistence.Persistence was the
cause for a ClassNotFoundError. Adding a jar like javaee-api-7.0 jar made this
class available for the app to be launched properly but cause aspects like
metrics+ logging completely lost from within the engine. The javaee-api jar was
interfering with the interface definitions of the Apex Engine libraries. The
workaround that worked was trying to push in hibernate-jpa-api jar which also
provided the missing classes.
Here is a possible explanation that might be causing this :
Suspect that there is an issue with the classloader ( note that this is a guess
only based on observations). The code works fine in a unit test end to end
using the local mode.
- This happens only for apps that have other JSR 303 based annotations (
Hibernate + Spring + JPA annotations in the code as was my case)
- Apex engine uses the Apache BVal in spite of other validation jars being
present in the application jars list
- In this process, the Apex engine is trying to use its classloader to
locate the jars that are expected to be part of the current class being loaded
( import statements) while being launched.
- At this juncture, it fails with a class not found error/exception.
The stack trace that was thrown for the hibernate based app was :
An error occurred trying to launch the application. Server message:
java.lang.NoClassDefFoundError: javax/persistence/Persistence at
org.apache.bval.jsr303.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:34)
at
org.apache.bval.jsr303.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:60)
at
org.apache.bval.jsr303.resolver.CachingTraversableResolver.isReachable(CachingTraversableResolver.java:82)
at
org.apache.bval.jsr303.ConstraintValidation.isReachable(ConstraintValidation.java:241)
at
org.apache.bval.jsr303.ConstraintValidation.validate(ConstraintValidation.java:166)
at
org.apache.bval.jsr303.ConstraintValidation.validate(ConstraintValidation.java:141)
at
org.apache.bval.util.ValidationHelper.validateProperty(ValidationHelper.java:233)
at
org.apache.bval.util.ValidationHelper.validateBean(ValidationHelper.java:216)
at
org.apache.bval.jsr303.ClassValidator.validateBeanNet(ClassValidator.java:393)
at org.apache.bval.jsr303.ClassValidator.validate(ClassValidator.java:149) at
com.datatorrent.stram.plan.logical.LogicalPlan.validate(LogicalPlan.java:1672)
at com.datatorrent.stram.StramClient.<init>(StramClient.java:161) at
com.datatorrent.stram.client.StramAppLauncher.launchApp(StramAppLauncher.java:509)
at com.datatorrent.stram.cli.DTCli$LaunchCommand.execute(DTCli.java:2050) at
com.datatorrent.stram.cli.DTCli.launchAppPackage(DTCli.java:3456) at
com.datatorrent.stram.cli.DTCli.access$7100(DTCli.java:106) at
com.datatorrent.stram.cli.DTCli$LaunchCommand.execute(DTCli.java:1895) at
com.datatorrent.stram.cli.DTCli$3.run(DTCli.java:1449) Fatal error encountered
It may be noted that the Application client driver class ( That extends the
streaming application ) loads the application context of Spring from within the
populateDAG() method. The operator code also injected a few Spring beans. Code
snippet below : (GlobalConfigRepository and
AppConfigRepository are Spring Data based repository definitions)
@ApplicationAnnotation
public class CassandraEventDetailsStreamingApp implements StreamingApplication {
GlobalConfigRepository globalConfigRepository;
AppConfigRepository appConfigRepository;
@Override
public void populateDAG(DAG dag, Configuration configuration) {
injectContext();
EventDetailsIngestionTopicKafkaOperator kafkaOperator =
getOperatorForEventDetailsStream();
EventDetailsFormatterOperator formatterOperator =
getFormatterOperator();
EventDetailsCassandraOutputoperator cassandraOutputoperator =
getCassandraWriter();
dag.addOperator("kafkaIngestor",kafkaOperator);
dag.addOperator("eventDetailsFormatter",formatterOperator);
dag.addOperator("eventDetailsCassandraWriter",cassandraOutputoperator);
dag.addStream("eventsFromAPI", kafkaOperator.eventDetailsAsJSONString,
formatterOperator.kafkaStreamInput);
dag.addStream("eventDetailsCassandraWrites",
formatterOperator.writeToCassandra,
cassandraOutputoperator.transformedJSON);
}
/**
* Injects all of the required context
*/
private void injectContext() {
globalConfigRepository = (GlobalConfigRepository)
CassandraEventDetailsAppContext.getCassandraEventDetailsAppContext().
getIOCContext().getBean(DWHAppBeanNames.GLOBAL_CONFIG_REPOSITORY_BEAN_NAME);
appConfigRepository = (AppConfigRepository)
CassandraEventDetailsAppContext.getCassandraEventDetailsAppContext().
getIOCContext().getBean(DWHAppBeanNames.APPCONFIG_REPOSITORY_BEAN_NAME);
}
..... ( Code snipped ) ..........
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)