Since the Log4j2 documentation unfortunately doesn't have any examples for specifying a JDBC Appender using a ConnectionFactory in a log4j2.yaml-configuration, i'd like to ask for a proper example.
This is my current state of the log4j2.yml:
Configuration:
//...
Appenders:
JDBC:
name: DataBase
connectionSource:
class: "com.example.config.Log4jConnectionFactory"
method: "getDbConnection"
tableName: "application_log"
columnConfigs:
- name: "log_date"
isEventTimestamp: true
- name: "log_level"
pattern: "%level"
- name: "logger"
pattern: "%logger"
- name: "user_id"
pattern: "$${ctx:userId}"
- name: "user_name"
pattern: "$${ctx:username}"
- name: "log_message"
pattern: "%message"
- name: "exception"
pattern: "%exception"
//...
And here the associated ConnectionFactory:
public class Log4jConnectionFactory {
private static BasicDataSource dataSource;
private Log4jConnectionFactory() { }
public static Connection getDbConnection() throws SQLException {
if (dataSource == null) {
dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:h2:mem:example-db;DB_CLOSE_DELAY=-1");
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUsername("sa");
dataSource.setPassword("");
}
return dataSource.getConnection();
}
}
With this configuration above Log4j throws the following error:
No factory method found for class org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender
The complete error log:
2023-02-03 09:38:08,479 main ERROR Unable to locate plugin type for connectionSource
2023-02-03 09:38:08,481 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,481 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,481 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,482 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,482 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,482 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,482 main ERROR Unable to locate plugin type for columnConfigs
2023-02-03 09:38:08,566 main ERROR Unable to locate plugin for connectionSource
2023-02-03 09:38:08,566 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,566 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,567 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,567 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,567 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,567 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,567 main ERROR Unable to locate plugin for columnConfigs
2023-02-03 09:38:08,569 main ERROR Could not create plugin of type class org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender for element JDBC: java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.config.plugins.util.PluginType.getElementName()" because "childType" is null java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.config.plugins.util.PluginType.getElementName()" because "childType" is null
at org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor.findNamedNode(PluginElementVisitor.java:104)
at org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor.visit(PluginElementVisitor.java:88)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.injectFields(PluginBuilder.java:187)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:123)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:137)
at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:61)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:47)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:391)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)
at com.example.Application.<clinit>(Application.java:13)
2023-02-03 09:38:08,571 main ERROR Unable to invoke factory method in class org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender for element JDBC: java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.findFactoryMethod(PluginBuilder.java:260)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:136)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:137)
at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:61)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:47)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:391)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)
at com.example.Application.<clinit>(Application.java:13)
Since I'm not sure whether the Appender structure is correct or not, and since I haven't found anything anywhere how this shoud be done in a YAML config file, and since the Log4j2 documentation isn't any help either, I'd like to ask for any help that can provide some clarification.
Many thanks in advance
Since this didn't leave me any peace, I invested a few extra hours and tried out many possible combinations and setups. In the end I came up with the following proper working solution:
log4j2.yaml:
Configuration:
//...
Appenders:
JDBC:
name: DataBase
ConnectionFactory:
class: "com.example.config.Log4jConnectionFactory"
method: "getDbConnection"
tableName: "application_log"
Column:
- name: "log_date"
isEventTimestamp: true
- name: "log_level"
pattern: "%level"
- name: "logger"
pattern: "%logger"
- name: "user_id"
pattern: "$${ctx:userId}"
- name: "user_name"
pattern: "$${ctx:username}"
- name: "log_message"
pattern: "%message"
- name: "exception"
pattern: "%exception"
//...
ConnectionFactory:
public class Log4jConnectionFactory {
private static final HikariDataSource dataSource;
static {
System.out.println("====================== This is Log4jConnectionFactory speaking ======================");
dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:h2:mem:example-db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;INIT=RUNSCRIPT FROM './src/db/h2/schema-log4j2.sql'");
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUsername("sa");
dataSource.setPassword("");
}
private Log4jConnectionFactory() { }
public static Connection getDbConnection() throws SQLException {
return dataSource.getConnection();
}
}
schema-log4j2.sql:
CREATE TABLE IF NOT EXISTS `application_log` (
application_log_id INTEGER GENERATED BY DEFAULT AS IDENTITY,
log_date TIMESTAMP,
log_level VARCHAR(10),
logger VARCHAR(100),
user_id BIGINT,
user_name VARCHAR(50),
log_message TEXT,
exception TEXT,
PRIMARY KEY (application_log_id)
);
Since we are in a Spring Boot environment and an H2 database is used, we have to consider that both logger and database have to be ready for use at a point, where Spring Boot itself is still in the initialization phase. Therefore logger and database must be setup without the help of Spring Boot, respectively without the application.yml configuration file.
So since schema creation can't be done via config file, we assign this task to the H2-connection-string. However, this means that every time a connection is requested, the schema creation is processed. To not run into an error see the detail CREATE TABLE IF NOT EXISTS.
Also to be mentioned, the connection data is currently hardcoded. This is definitely not a great solution, and I'm still looking for a way to work around this. A lookup to the Spring context is not possible due to timing reasons already mentioned. JNDI doesn't make much sense either, since the Tomcat configuration for this happens also too late. Let's see what solution eventually it will be. If I'll find one, I will update this post.
Related
Overview
I set up a github repo for this question to provide as much of the boiled down environment as possible.
My goal is to set up ebean ORM for database manangement from a Paper Minecraft plugin. I'm able to shade in the ebean dependencies, but creating a query using "io.ebean:ebean-querybean:" throws an error saying that it cannot find an implementation of SpiRawSqlService.
Environment
Paper Minecraft: paper-1.19.3-367.jar
Java 18
Ebean enhancement plugin for IntelliJ(I checked that I have it enabled for this project)
io.ebean gradle plugin version 13.10.0
shadowJar gradle plugin version 7.1.2
The Stacktrace
Everything is fine setting up the database, and saving to the Database. Queries without using a querybean work fine as well. The error is thrown when initializing any class containing a reference to a generated querybean.
The error outputted is printed the latest.log
Caused by: java.lang.IllegalStateException: No service implementation found for interface org.example.ebean.io.ebean.service.SpiRawSqlService
The stacktrace tells us that it couldn't find org.example.ebean.io.ebean.service.SpiRawSqlService.
Looking at the decompiled shadowJar after package relocation, the implementation for this class is found at org.example.ebean.io.ebeaninternal.server.rawsql.DRawSql;
Printing out the ClassLoader#getDefinedPackages on the instance supplied when creating the ebean Database connection results in this:
org.example.ebean
org.example.ebean.database
org.example.ebean.io.ebean
org.example.ebean.io.ebean.annotation
org.example.ebean.io.ebean.config
org.example.ebean.io.ebean.config.dbplatform
org.example.ebean.io.ebean.datasource
org.example.ebean.io.ebean.meta
As you can see, the org.example.ebean.io.ebeaninternal package and subpackages are not outputted in this list.
Underlying issue
How/where is the package "ebeaninternal" being loaded if at all? How can I get the enhanced querybean to find this package so it can load the implementation (DRawSql) of SpiRawSqlService?
Reasoning
Bukkit's #EventHandler utilizes a different contextClassLoader than the ClassLoader that loads the ebean classes/services (contained in the ShadowJar).
The error states No service implementation found because the thread that is initializing the querybean does not have access to that class.
Explained Solution
The solution here is to use Thread#setContextClassLoader() to use the same ClassLoader used when calling DatabaseFactory.createWithContextClassLoader(). Set the ClassLoader, initialize every Class that uses a QueryBean, revert the ClassLoader to what it originally was.
EBean might be able to solve this problem. But for now, a fix is to just call an empty init method on every class that becomes an Enhanced-QueryBean from a thread that is using the proper ContextClassLoader
Full Example
I pushed the full example containing the fix to the original github repo
Basic Example
DatabaseSetup.java
public static void load() {
DataSourceConfig dataSourceConfig = configureDataSource();
DatabaseConfig dbConfig = configureDatabase(dataSourceConfig);
// We should use the classloader that loaded this plugin
// because this plugin has our ebean dependencies
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader pluginClassLoader = BukkitEBeanPlugin.class.getClassLoader();
// create the DatabaseFactory with the classloader containing ebean dependencies
DatabaseFactory.createWithContextClassLoader(dbConfig, pluginClassLoader);
// Set the current thread's contextClassLoader to the classLoader with the ebean dependencies
// This allows the class to initialize itself with access to the required class dependencies
Thread.currentThread().setContextClassLoader(pluginClassLoader);
// invoke the static initialization of every class that contains a querybean.
// Note that any method in the class will initialize the class.
FindByQueryBean.init();
// Restore the contextClassLoader to what it was originally
Thread.currentThread().setContextClassLoader(originalClassLoader);
BukkitEBeanPlugin.get().getLogger().info("Successfully created database");
}
...
}
FindByQueryBean.java
public static void init() {
// intentionally empty
}
I've got a Quarkus project where DynamoDBMapper is also being used. Everything runs perfectly in dev mode.
But when running this command mvn package -Pnative -pl my-module -DskipTests it gives me this error
[my-module-1.0-SNAPSHOT-runner:61] [total]: Error: Unsupported features in 2 methods
Detailed message:
Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected. To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Trace: Object was reached by
reading field com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy.random of
constant com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy#2ad70ff4 reached by
reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.equalJitterBackoffStrategy of
constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy#64d81db reached by
reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
constant com.amazonaws.retry.RetryPolicy#7ce3fed7 reached by
scanning method com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory.getDefaultConfig(AmazonDynamoDBClientConfigurationFactory.java:31)
Call path from entry point to com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory.getDefaultConfig():
at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory.getDefaultConfig(AmazonDynamoDBClientConfigurationFactory.java:31)
at com.amazonaws.ClientConfigurationFactory.getConfig(ClientConfigurationFactory.java:36)
at com.amazonaws.client.builder.AwsClientBuilder.resolveClientConfiguration(AwsClientBuilder.java:169)
at com.amazonaws.client.builder.AwsClientBuilder.access$000(AwsClientBuilder.java:54)
at com.amazonaws.client.builder.AwsClientBuilder$SyncBuilderParams.<init>(AwsClientBuilder.java:505)
at com.amazonaws.client.builder.AwsClientBuilder.getSyncClientParams(AwsClientBuilder.java:441)
at com.amazonaws.client.builder.AwsSyncClientBuilder.build(AwsSyncClientBuilder.java:46)
at integration.common.config.DynamoDBConfig.dynamoDBMapper(DynamoDBConfig.java:23)
at integration.common.config.DynamoDBConfig_ProducerMethod_dynamoDBMapper_f166ddedc44150bc6c5ef50fafe7a64b599d849a_Bean.create(Unknown Source)
at integration.common.config.DynamoDBConfig_ProducerMethod_dynamoDBMapper_f166ddedc44150bc6c5ef50fafe7a64b599d849a_Bean.create(Unknown Source)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:111)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:32)
at com.oracle.svm.core.jdk.SystemPropertiesSupport.initializeLazyValue(SystemPropertiesSupport.java:216)
at com.oracle.svm.core.jdk.SystemPropertiesSupport.getProperty(SystemPropertiesSupport.java:169)
at com.oracle.svm.core.jdk.Target_java_lang_System.getProperty(JavaLangSubstitutions.java:287)
at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_ARRAY_System_getProperty_deeeaa72a006d330408a3b7d002c7533e108bc28(generated:0)
The dependency for DynamoDBMapper in pom.xml
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.12.205</version>
</dependency>
The configuration class
#ApplicationScoped
public class DynamoDBConfig {
#ConfigProperty(name = "DYNAMO_DB_TABLE_NAME")
String tableName;
#Produces
public DynamoDBMapper dynamoDBMapper() {
return new DynamoDBMapper(
AmazonDynamoDBClientBuilder.standard().build(),
tableNameConfig()
);
}
private DynamoDBMapperConfig tableNameConfig() {
return new DynamoDBMapperConfig.Builder()
.withTableNameOverride(TableNameOverride.withTableNameReplacement(
tableName)).build();
}
}
I've found out that this AmazonDynamoDBClientBuilder.standard().build() specific line is causing this issue.
I've tried adding com.amazonaws to application.properties to solve this issue. Which it does locally with the previous command but fails in a aws lambda when it runs.
quarkus.native.additional-build-args=--initialize-at-run-time=org.apache.http.impl.auth.NTLMEngineImpl\
\\,io.netty.util.internal.logging.Log4JLogger\
\\,com.amazonaws
We've added a filter to our spring webapp that checks all incoming requests for anything that could cause an XSS vulnerability. However, when it tries to write to the log, we get the following stack trace:
com.blah.blah.web.controllers.ExceptionLoggingController - ERROR: Exception: code=500,uri=/post.html,servlet=dispatch,class=org.owasp.esapi.errors.ConfigurationException,from=1.2.3.4,message=Request processing failed; nested exception is org.owasp.esapi.errors.ConfigurationException: java.lang.IllegalArgumentException: Classname cannot be null or empty. HTTPUtilities type name cannot be null or empty.
org.owasp.esapi.errors.ConfigurationException: java.lang.IllegalArgumentException: Classname cannot be null or empty. HTTPUtilities type name cannot be null or empty.
at org.owasp.esapi.util.ObjFactory.make(ObjFactory.java:105)
at org.owasp.esapi.ESAPI.httpUtilities(ESAPI.java:121)
at org.owasp.esapi.ESAPI.currentRequest(ESAPI.java:70)
at org.owasp.esapi.reference.JavaLogFactory$JavaLogger.log(JavaLogFactory.java:308)
at org.owasp.esapi.reference.JavaLogFactory$JavaLogger.warning(JavaLogFactory.java:242)
at org.owasp.esapi.reference.DefaultEncoder.canonicalize(DefaultEncoder.java:181)
at org.owasp.esapi.reference.DefaultEncoder.canonicalize(DefaultEncoder.java:120)
at com.blah.blah.web.MyFilter.removeXSS(MyFilter.java:26)
I have ESAPI.properties on the classpath, that seems to be otherwise working, that does have the "missing" class configured:
ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
And DefaultHTTPUtilities is on the classpath as well.
It turns out I was also importing a library called opensaml (as a dependency of some other dependency). This library has its own implementation of SecurityConfiguration, which is the interface ESAPI uses to load configuration. For some reason the opensaml implements nearly all the methods to just return null or 0:
package org.opensaml;
/**
* Minimal implementation of OWASP ESAPI {#link SecurityConfiguration}, providing the support used within OpenSAML.
*/
public class ESAPISecurityConfig implements SecurityConfiguration {
/** Constructor. */
public ESAPISecurityConfig() {
}
// snip...
/** {#inheritDoc} */
public String getHTTPUtilitiesImplementation() {
return null;
}
// snip....
}
In a class called DefaultBootstrap, this was getting executed somewhere during the startup of my application, which overrides ESAPI's default implementation:
protected static void initializeESAPI() {
ESAPI.initialize("org.opensaml.ESAPISecurityConfig");
}
I couldn't get rid of the opensaml library, so I had to change my code so that before I invoke ESAPI, I override it back to the default implementation:
ESAPI.initialize("org.owasp.esapi.reference.DefaultSecurityConfiguration");
value = ESAPI.encoder().canonicalize(value);
Following up on Suresh's comment...Toward that end, look at wherever you captured stdout and look for "Attempting to load ESAPI.properties" and follow that trail. It should look something like this:
Attempting to load ESAPI.properties via file I/O.
Attempting to load ESAPI.properties as resource file via file I/O.
Not found in 'org.owasp.esapi.resources' directory or file not readable: /home/kww/Code/GitHub/kwwall/esapi-java-legacy/ESAPI.properties
Found in SystemResource Directory/resourceDirectory: /home/kww/Code/GitHub/kwwall/esapi-java-legacy/target/test-classes/esapi/ESAPI.properties
Loaded 'ESAPI.properties' properties file
And them make sure that it is loading ESAPI.properties from where you expected it to be loaded.
I have the following class:
package com.spring.domain;
#Document(collection = "sportactions") // for my mongodb collection
#JsonInclude(JsonInclude.Include.NON_NULL)
public class SportAction extends Action {
//code logic
}
When I compile it, it gives me the following error:
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Handler processing failed; nested exception is
java.lang.NoClassDefFoundError: com/spring/domain/Sportaction (wrong
name: com/spring/domain/SportAction)] with root cause
java.lang.NoClassDefFoundError: com/spring/domain/Sportaction (wrong
name: com/spring/domain/SportAction)
I was confused as I can see my class is called SportAction with a capital A and not a small letter a so then I attempted to refactor my class name to see if it will work with a small letter a.
I got the following error:
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Handler processing failed; nested exception is
java.lang.NoClassDefFoundError: com/spring/domain/SportAction (wrong
name: com/spring/domain/Sportaction)] with root cause
java.lang.NoClassDefFoundError: com/spring/domain/SportAction (wrong
name: com/spring/domain/Sportaction)
The spring application will compile perfectly but this will appear at run time when I try to use the class.
I also did several clean and then build on gradle and it still doesn't work.
Does anyone know what is wrong with the code?
The error arose in this line of my java code when I try to fetch a list of Sportaction from mongodb:
List<Sportaction> sportactions = mongoTemplate.find(query, Sportaction.class);
I don't know why this error occurred, but my build.gradle file required me to build a jar like so:
task stage(type: Copy, dependsOn: [clean, build]) {
from jar.archivePath
into project.rootDir
rename {
'app.jar'
}
}
stage.mustRunAfter(clean)
clean << {
project.file('app.jar').delete()
}
When I ran it and pushed it onto my repo, I got a very strange error where my filename was now SportAction but my class name inside my java file was:
public class Sportaction
This caused a mismatch, and I tried refactoring the name to match the filename SportAction but the same wrong name error arose. I then decided to refactor the name to something else like SportEvents and then rerun the code and then it worked.
This isn't the best solution but it will have to do for now. I suspect it has something to do with the way the jar was built but I'm not sure as the app.jar was never run. The Application.main() was the class that ran when I ran my Spring app.
I'm also confused as to why my SportAction class on bitbucket does not seem to have a commit at all - see those 3 dots next to my Action file - it doesn't have a date and neither does it have a description.
This is my code where I am trying to access a flowvariable named "question"
import org.mule.api.MuleEventContext;
import org.mule.api.MuleMessage;
public class Main {
public Object onCall(MuleEventContext eventContext) throws Exception {
MuleMessage msg = eventContext.getMessage();
msg.getInvocationProperty("Question");
return msg;
}
}
but I am getting the following error:
Message : Failed to find entry point for component, the following resolvers tried but failed: [
CallableEntryPointResolver: Object "Main#2cad86ee" does not implement required interface "interface org.mule.api.lifecycle.Callable"
ReflectionEntryPointResolver: Could not find entry point on: "Main" with arguments: "{class [B}"
AnnotatedEntryPointResolver: Component: Main#2cad86ee doesn't have any annotated methods, skipping.
MethodHeaderPropertyEntryPointResolver: The required property "method" is not set on the event
]
Code : MULE_ERROR-321
--------------------------------------------------------------------------------
Exception stack is:
1. Failed to find entry point for component, the following resolvers tried but failed: [
CallableEntryPointResolver: Object "Main#2cad86ee" does not implement required interface "interface org.mule.api.lifecycle.Callable"
ReflectionEntryPointResolver: Could not find entry point on: "Main" with arguments: "{class [B}"
AnnotatedEntryPointResolver: Component: Main#2cad86ee doesn't have any annotated methods, skipping.
MethodHeaderPropertyEntryPointResolver: The required property "method" is not set on the event
] (org.mule.model.resolvers.EntryPointNotFoundException)
org.mule.model.resolvers.DefaultEntryPointResolverSet:49 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/model/resolvers/EntryPointNotFoundException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
org.mule.model.resolvers.EntryPointNotFoundException: Failed to find entry point for component, the following resolvers tried but failed: [
CallableEntryPointResolver: Object "Main#2cad86ee" does not implement required interface "interface org.mule.api.lifecycle.Callable"
ReflectionEntryPointResolver: Could not find entry point on: "Main" with arguments: "{class [B}"
AnnotatedEntryPointResolver: Component: Main#2cad86ee doesn't have any annotated methods, skipping.
MethodHeaderPropertyEntryPointResolver: The required property "method" is not set on the event
]
at org.mule.model.resolvers.DefaultEntryPointResolverSet.invoke(DefaultEntryPointResolverSet.java:49)
at org.mule.component.DefaultComponentLifecycleAdapter.invoke(DefaultComponentLifecycleAdapter.java:339)
at org.mule.component.AbstractJavaComponent.invokeComponentInstance(AbstractJavaComponent.java:82)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
Well, the error message is pretty clear:
Object "Main#2cad86ee" does not implement required interface "interface org.mule.api.lifecycle.Callable"
Just implement this interface and life will be peachy.