Add a class file to a project class loader - java

I have managed to add a custom class to a user's project(in Blue J). I am developing inside eclipse.
I was just wondering if anyone could help with the theory of what to do after adding the java file to the project directory and then compiling it.
I have a class file and a java file inside the user's project but I assume that I need to add it to the class loader being used in BlueJ.
I have tried a number of ways but keeping getting ClassNotFoundException
My best attempt so far is:
/**
* #param cLoader the bluej class loader inside eclipse
* #param packageName the name of the package the bluej project belongs to
*/
public void addURL(ClassLoder cLoader, String packageName)
{
try
{
ClassLoader classLoader = cLoader;
classLoader.loadClass(packageName);
}
catch(ClassNotFoundException e)
{
//do something
}
}

Related

get the execution location from within a library jar

I have a class named Utils with a static method that should determine the execution location.
public class Utils {
public static Path getExecutionLocation() throws URISyntaxException {
return Paths.get(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
Within eclipse this gives me: C:\Users\USERNAME\workspace\PROJECT\bin\main\
Run as a jar this gives me: C:\PATH\TO\JAR\thatJar.jar
Both is correct and expected.
Now I have that Utils class inside a library called someLib.jar.
When I use that library in another project it works if I build a jar of that project with someLib.jar inside.
But in eclipse it returns the path to someLib.jar.
I want it to return the path to the execution directory of the project:
C:\Users\USERNAME\workspace\A_PROJECT_USING_SOMELIB\bin\main\
I tried
return new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).toPath();
But that failed inside a jar because getResource(".") results in null.
I could give getExecutionLocation a class from inside the project as a parameter and excute getProtectionDomain() on that. But I want to ask here if someone knows a better solution.
Try this:
public class Utils {
public static Path getExecutionLocation(Class c) throws URISyntaxException {
return Paths.get(c.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
So you pass the class as an argument to the function. For example:
public class Main
{
public static void main(String[] args)
{
Utils.getExecutionLocation(Main.class);
}
}
Note that there may be more straightforward solutions,
But this is the first one that came into my mind, and I thought, why not :)
I've found a solution based on ClassLoader.getSystemClassLoader() approach that gives me the class loader responsible for the main entry point of the project that is using someLib.jar.
Within an IDE I can use getResource(".") to get URL of the root path of all resources (and sources).
From jar file this does not work. So I use getResource("META-INF") to get URL of the META-INF folder (that has the manifest inside) and should always exist in jar files.
Maybe still not optimal. But so far I can work with it.
public static Path getExecutionLocation() throws URISyntaxException, IOException {
// System ClassLoader is on the highest level and responsible for the main entry point
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// get the resources root path (works within IDEs)
URL executionLocation = systemClassLoader.getResource(".");
// fallback for jars
if(executionLocation == null) {
// look for META-INF folder
URL metaInfLocation = systemClassLoader.getResource("META-INF");
// URL looks like "jar:file:/C:/path/to/jar/jarfile.jar!/META-INF"
// openConnection on URL - does not really establish connection but checks if URL would be valid
JarURLConnection connection = (JarURLConnection) metaInfLocation.openConnection();
// extracts URL to jar file
executionLocation = connection.getJarFileURL();
}
// impossible to determine
if(executionLocation == null) throw new RuntimeException("Impossible to determine exeution location");
return Paths.get(executionLocation.toURI());
}

how to checks If there exist duplicate class with specified class name in Java Runtime Enviroment?

My application can not run normal when it has duplicate class, with problem like 'no such method'.
The project have two class with the same class name , one is from project code, another is from a jar file. how to check this problem when application start up?
src/main/java/com/kxw/Example.java
gradle.build
compile("com.kxw:xxx:1.0")//contains com.kxw.Example
I expect there has java api or utils to check when application start up .
public void startUp(){
if(existDuplicateClass("com.kxw.Example")){
shutdown();
}
}
protected boolean existDuplicateClass(String className){
//TODO
}
i don't konw how to implement method existDuplicateClass.
refenence:
Gradle: how to check duplicate class in project?
finally i check duplicate class when startup by this way :
String classPath = Optional.ofNullable(xx.class.getProtectionDomain())
.map(ProtectionDomain::getCodeSource)
.map(CodeSource::getLocation)
.map(URL::getPath).orElse("");
//class is not from common-core.jar
if (!classPath.contains("common-core")) {
log.error("{} thrift class may be duplicate ...", xx.class.getName());
shutdownContext.shutdown();
}

Main class not found in project IntelliJ IDEA: Java Application

IntelliJ does not find a main class in my Java application project. The project was cloned from a git repository so had no run configuration. I go to Edit Configurations, add a new Application template, go to Main class: and it says "No matches found in project".
So, manually searching through the hierarchy I find the .java file that contains the main function but it will not accept it as the main class. I've pasted the file below to prove that it has the correct main function.
public class AdvanceWarsGameHandler implements IGame
{
private Image mImage;
private String mTitle;
public AdvanceWarsGameHandler()
{
mTitle = "Advance Wars Game";
mImage = new Image("/OffBrandCerealOopsAllCarries2-01.png");
}
//Game logic unrelated to graphics goes here
#Override
public void update(Game game, float deltaTime)
{
}
//Update, but for graphics
#Override
public void render(Game game, Renderer renderer)
{
renderer.drawImage(mImage, game.getInput().getMouseX(), game.getInput().getMouseY());
}
public static void main(final String args[])
{
//Creating and starting an instance of AdvanceWarsGameHandler
AdvanceWarsGameHandler advancewars = new AdvanceWarsGameHandler();
Game myGame = new Game(advancewars);
myGame.start();
}
public String getTitle()
{
return mTitle;
}
}
So the question is, why is the IntelliJ project not recognizing the main function in this file, or what is IntelliJ looking for as the "Main class" of an application?
Okay, hopefully this answer will help others who are unfamiliar with IntelliJ IDEA.
The solution came in two parts
Part 1: Missing compilation directory.
Since I did not create the project from new and instead I cloned a Git repository, there was no default compilation directory set up.
To access this in IntelliJ IDEA go to File -> Project Structure -> Project and set the "Project compiler output" so the project can actually compile.
Part 2: Setting up the modules
The original project was created in Eclipse which has packages. In order to get those packages to work in IntelliJ, I had to go to the Modules tab of the Project Structure menu and set my src and res folders as Source and Resource Folders. This allowed IntelliJ to find the main() function in my class and the program ran as expected.
This solved my problem though if any of you IntelliJ users out there can see anything bad about what I did to get it working, please comment.

Pentaho Data Integration User Defined Java Class

I create simple java class and export it to jar:
package test;
public class Test {
public Test() {
// TODO Auto-generated constructor stub
}
}
Jar file add to lib folder in Pentaho (there are many jar files)
Next step I want to use my class in Pentaho Data Integration so I created User Defined Java Class:
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
test.Test t = new test.Test();
return true;
}
When I click Test class I get the following information:
Line 3, Column 12: Class "test.Test" not found
So I have a question: Where is the mistake and why is the class not found?
Try checking the launcher.property file inside the /design-tools/data-integration/launcher folder. Make sure that the classpath and the libraries are having the path of the jar defined. Since you have placed your JAR file inside the lib folder, look for that.
Restart the Spoon after editing and it would work ideally.
I have placed the code inside the libext folder, so i have added :../libext to the classpath and libraries. And below is the code snip:
In case it still throws an error, try checking the Java code again. I assume something might have gone wrong there.
Also documented the above in here.
Hope it helps :)

Java project that uses library throws NoClassDefFoundError when using project that uses the same library

I'm creating a Java library for using in other Java projects. The projects use Repast Symphony and my library does so too (so i'm afraid this error is being caused by some conflict). Everything builds fine, but when I run a the Repast simulation, it throws java.lang.NoClassDefFoundError: repast/simphony/context/Context
I tried exporting my library as a jar, importing the project directly and adding the library to my project's classpath, to no avail. What can I be doing wrong?
This Context class is being used in both my library and my projects. The following is a snippet of it use in two classes:
// MyContextBulder.java
// This file is in my project
// This class is called by Repast first
import repast.simphony.context.Context;
import repast.simphony.dataLoader.ContextBuilder;
import mylibrary.core.DF;
import mylibrary.core.DF.MyContext;
public class MyContextBuilder implements ContextBuilder<Object> {
#Override
public Context<Object> build(Context<Object> context) {
context.setId("test");
DF.setContext((MyContext) context);
// Create agent
new MyAgent();
// Add the agent to the Repast context.
// context.add(t);
return context;
}
}
// DF.java
// This file is in my library
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.commons.collections15.Predicate;
import repast.simphony.context.Context;
import repast.simphony.context.ContextListener;
import repast.simphony.space.projection.Projection;
import repast.simphony.util.collections.IndexedIterable;
import repast.simphony.valueLayer.ValueLayer;
import mylibrary.Agent;
/**
* This static class provides the Directory Facilitator Service
* and is used to send messages to agents
* and to keep a directory of all agents in the application.
* Agents use the static method send(ACLMessage) to send a message
* to one or more agents. The ACLMessage object contains
* the receiver agent and the sender (so the receiver can reply back).
*
* This class needs to be setup initially before registering new agents.
* To do that, simply call setContext(...);
* #author joaolopes
*
*/
public class DF {
private static int lastAID = 0; // Just to help generate new identifiers
private static HashMap<Integer, Agent> agents; // Contains all agents
/**
* The Repast context that contains all
* scheduled Repast objects.
*/
private static MyContext context = null;
/**
* Registers the agent in the directory and returns its
* AID (freshly generated for it). If the agent is already
* registered, returns its current AID.
* #param agent The agent to be registered
* #return The AID generated for the agent.
*/
public static int registerAgent(Agent agent) {
// If this agent is already in the hashMap,
// just return its key.
if (getAgents().containsValue(agent)) {
return agent.getAID();
}
// Quick way to find a new ID for this agent
// that is not in use at the moment.
while (getAgents().containsKey(lastAID)) {
lastAID++;
}
// The agent must know their own ID.
agent.setAID(lastAID);
agents.put(lastAID, agent);
System.err.println(context.toString());
context.add(agent);
return lastAID;
}
public static void setContext(MyContext c){
context = c;
}
}
Editing to add relevant info from the comments:
I don't import the repast JAR directly in my projects as I do in my library. Repast Symphony is installed in Eclipse as a plugin, so I created "Repast Projects" that include all Repast libraries. Therefore, I'm unable to remove the specific JAR that is causing the possible conflict of classes.
Exactly as you said. This error should be the conflict between the same classes in a jar. If you are using an IDE try to clean the build and rebuild again.
And also I would suggest you to use only one symphony library jar. Multiple class definitions always leads to ambiguity for the JVM class loader.
Try not to use symphony jar in the importing project since you already have it in your exported jar. After importing your lib, there should no errors.
Try this and let me know how it goes.
I suggest that you use an build tool. Something like Maven. Then maven with the right plugin will fix this problem for you. All you need to do, is to tell Maven that you need a particular jar file. Then a magic will occur, and you will have a well working jar-file to distribute
java.lang.NoClassDefFoundError is thrown when the JVM tries to run the application. Typical cases is when you got one jar-file as "interface". Then you got other jar-file that implement that interface.
So what you need to do, is that have the Repast jar inside your jars classpath. So that your program can find the right class you want to use.

Categories