How to manage dependency on servlet-api? - java

We have a web maven module that is compiled to a war, and thus doesn't need to include the servlet-api jar directly. We use <scope>provided</scope> for this.
The problem arises when I try to write a small main() to test one of my classes. This is not a unit test, but rather resides with the code itself.
This fails on java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest:
public static void main(String[] args) {
final Injector injector = Guice.createInjector(new StandardModule());
// StandardModule is our standard module, with bindings to
// something that rightfully depends on servlet API
...
}
Besides splitting my module to two or three different modules, is there an easy workaround I haven't thought of?
Perhaps the best solution is to move this tester to the test code.

You can use <scope>test</scope> if you want to have it for tests. However provided works fine for me in Eclipse - it is added to the classpath.

If you use eclipse with m2eclipse, <scope>provided</scope> will be resolved correctly and your main class will compile and run properly.

Related

NoSuchMethodError: 'int kafka.utils.TestUtils.boundPort(kafka.server.KafkaServer, org.apache.kafka.common.security.auth.SecurityProtocol)' [duplicate]

I am trying to write a unit test test case for kafka producer/consumer and came across a simple example http://grokbase.com/t/kafka/users/13ck94p302/writing-unit-tests-for-kafka-code.
On using this code I figured the jar does not have Testutils class. I started some research on how to include this and find out that apache doesnot ship Testutils with the jar.
I do not understand the reason. Then found this https://issues.apache.org/jira/browse/KAFKA-1308 which asks me to run some gradle commands.
I am confused. Why do I need to do that? Is there a simpler way to write this unit test or include Testutils ?
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>0.8.2.1</version>
<classifier>test</classifier>
</dependency>
In general, you don't include test utilities in the main production jar. This pollutes the main code with test code which is unnecessary and bloats the most frequently used jar.
Try to find a separate kafka test jar or dependency and include that in your build system and you should be able to use the TestUtils class.

Camunda: cannot be cast to (same class)

I've included a .jar in my maven project writing this in pom.xml:
<dependencies>
<dependency>
<groupId>org.loopingdoge.acme.model</groupId>
<artifactId>acme-model</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/acme-model.jar</systemPath>
</dependency>
</dependencies>
acme-model.jar contains org.loopingdoge.acme.model.House but this cast
public class HouseAdder implements JavaDelegate {
public void execute(DelegateExecution delegateExecution) throws Exception {
House house = (House) delegateExecution.getVariable("house");
}
}
gives me this error when deployed on a Wildfly server:
18:50:20,255 ERROR [org.camunda.bpm.engine.context] (default task-45) ENGINE-16004 Exception while closing command context:
org.loopingdoge.acme.model.House cannot be cast to org.loopingdoge.acme.model.House: java.lang.ClassCastException: org.loopingdoge.acme.model.House cannot be cast to org.loopingdoge.acme.model.House
at org.loopingdoge.acme.services.HouseAdder.execute(HouseAdder.java:13)
Such cases happens when a class will be loaded over different classloaders. java make them distinct even if package and classname are identical.
You need to find out on which ways this class will be loaded. As first step, find the jars which contains that class.
or/and read this on SO
Ran into the same problem. Further analysis showed that two different class loaders were used, as stated in this thread already. In my case the culprit was devtools of spring boot, a tool which likely many will have active in their pom. Seems that devtools doesn't play well with (in my case) camunda java delegates with embedded camunda engine.
I guess that you have the class in multiple places, e.g. packaged the jar within WildFly and the WAR you deploy. Check that you have the class only one time on the classpath.
By the way: Better not use system dependencies if not absolutely necessary. This is what maven repositories are for.

Replace provided Maven dependency with local class

If I check my effective pom I will find the following entry:
<dependency>
<groupId>com.package.of.other.department</groupId>
<artifactId>someArtifact</artifactId>
<version>2.4.2</version>
<scope>provided</scope>
</dependency>
This comes from the parent pom that we have to use to let our software (bpmn processes) run on a company wide platform.
Now comes a hacky part. There will be a bigger change and we cannot use someArtifact anymore. Unfortunately that artifact gets called directly by all our processes (you design the process and configure the full qualified class name for an item) and can't just configure a different artifact, as that would most likely break a lot of the running processes.
The simple plan was to create a class with the same package name and with the same class name, remove every dependency to the original package and everything should work fine. During the tests I noticed that it doesn't use my new class but still the original one, most likely because it gets provided as dependency via the mandatory parent pom and for some reason prefers that over my local one.
Excluding a provided dependency from the parent pom doesn't seem to work that easily?! Any idea how I could solve my issue?
If the application is regular java, the class that will be load is the first class met in the classpath order.
If you use other runtime package dependency management, the strategy is different. As example you can adjust your import-package in OSGi to ensure the use a class contains in private-package.

How to add runtime dependency on another module?

I am writing an extension for a library which consists of several Maven modules. I need to add some functionality on top of one module but do not want to add unnecessary dependencies in case somebody wants to use this module without my extension (typical use case).
One solution that I can think of is to create another module with my extension and try to call methods from its classes using reflection. There would be some kind of check like this:
try {
Class.forName("my.package.Foo", false, getClass().getClassLoader());
// extension will be enabled and some method will be called using reflection
} catch(ClassNotFoundException e) {
// extension will be disabled
}
And methods on that class will only be called if it is on classpath. The extension can then be activated if you add Maven dependency on its module (in addition to the dependency on the module it extends).
But this does not sound like the best approach. Are there any more elegant solutions to this problem?
The one way is to use built-in Service provider interface (SPI).
The basic idea is to make your optional libraries to provide an implementations of some interface (a "services") which may be easily found by your main application. Take a look at this example
// scan classpath for all registered
// implementations of Module interface
ServiceLoader<Module> loader = ServiceLoader.load(Module.class);
for (Module module : loader) {
module.doSomething();
}
Once your optional dependency is in classpath service loader will find it.
You can find a lot of examples in "Creating Extensible Applications" tutorial from Oracle on how to make it.
The other way is to use dependency injection frameworks such as spring or google guice. These frameworks are also providing a classpath scanning mechanisms for automatic component discovery. This solution is a way more flexible but heavier than SPI.
you can definite your dependency like this:
<dependency>
<groupId>com.thoughtworks.paranamer</groupId>
<artifactId>paranamer</artifactId>
<version>2.6</version>
<optional>true</optional>
</dependency>
checkout the detail from this link
Simplest would be to create a new Module as you mentioned. And in this new Project A you have a dependency to this existing Module that you are talking about Project B.
So now any body who wants to use without your extension would use Project B. And anyone who would need your extension would use Project A.
Just make sure to add the Maven dependencies in the build Path to avoid ClassNotFound conflicts.

How do I determine which version of a class my object is?

I'm trying to write a plugin into a framework application (Joget). My plugin source looks something like this:
public class MyPlugin extends ExtDefaultPlugin implements ApplicationPlugin, ParticipantPlugin {
...
public void execute(){
...
SecurityContextImpl secContext = (SecurityContextImpl) WorkflowUtil.getHttpServletRequest().getSession().getAttribute("SPRING_SECURITY_CONTEXT");
}
}
When I run the plugin, I get the following exception.
java.lang.ClassCastException: org.springframework.security.context.SecurityContextImpl cannot be cast to org.springframework.security.context.SecurityContextImpl
I'm using Maven. Now since both have the same package name, I'm assuming I'm accidentally using the wrong package version in my plugin JAR (that contains the SecurityContextImpl class) than the one in the framework. But I've double-checked and it looks like I'm including the correct one in my plugin package.
Is there a way to see the classloader or source JAR of my class (e.g. using reflection in some manner)? Any other ideas on how to address this?
This type of java.lang.ClassCastException, where both classes names are equals, occur when the same class, or two class with the same name are loaded by 2 different classloaders.
I don't know Joget, but you are talking about plugin. Frameworks often load plugins in separate classloaders to ensure a proper isolation between them.
Since you say I've double-checked and it looks like I'm including the correct one in my plugin package., you may want to remove spring-security from your package, as it's probably already loaded by the framework classloader.
You're using Maven, so you may simply add <scope>provided</scope> to the spring-security dependency (but not sure, since we don't have your pom.xml)
I've got the same exception when I was running my plugin.
There are two cases in general:
1. The class is a local class.
And that is to say, there is no repository(groupId, artificateId, etc) to be deployed in the pom.xml of your plugin. The solution is, go the target folder and open the xxx-0.0.1-snapshot.jar file, then open META-INF/MANIFEST.MF, add the source file of that class /dependency/file.jar, then add the source jar to the dependency folder
Remarks: It is better to give a version of the your local file and add it as shown in your pom.xml to let it be found as src in your code.
<!-- your source jar need to be renamed as example-1.0.0.jar -->
<dependency>
<groupId>this.should.be.the.prefix.of.your.package</groupID>
<artificateId>file.name<artificateId>
<version>1.0.0</version>
<systemPath>${basedir}/lib/stclient_updated-1.0.0.jar</systemPath>
<scope>system</scope>
</dependency>
2. The class is a remote class with repository
I had this type of problem once because the repository is not correct, see also Maven Repository to find the official repository of the source.
I hope that it could help =)
Cheers

Categories

Resources