1

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.

ecc
  • 1,409
  • 16
  • 37
  • Extract resulting jar file and check if there this class or no. – Divers Mar 31 '14 at 16:55
  • This 'Context' class is not inside my library's jar. It's inside Repast's jar. The contents of Repast don't appear inside the jars I generate. I'm not sure I understood your suggestion though. I can use the missing class in my library project, but not in the project that uses my library. – ecc Mar 31 '14 at 17:04

2 Answers2

2

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

Viggo
  • 91
  • 6
Sri777
  • 502
  • 3
  • 9
  • This is probably the best solution, but the course of action is not evident to me because my projects are "Repast Projects" that include all repast simphony development libraries, while my library only imports the main repast simphony jar. I can't remove an individual jar from my projects. – ecc Mar 31 '14 at 17:44
  • @ecc I use ant for my builds. I really dont have much idea regarding maven. What I do in my build is I copy all my jars into a single directory, copy the directory to final jar, place the directory on classpath and reference them to project. So now I have only a single jar file to run my project. Using ANT it is really easy. I can send you a sample build.xml file if you need it. – Sri777 Apr 01 '14 at 13:49
  • I don't have access to the internals of Repast, as I said in the previous comment, but thanks for the tip. – ecc Apr 01 '14 at 15:16
1

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.

Viggo
  • 91
  • 6
  • I've got a manifest inside my library's jar with 'Class-Path: repast.simphony.bin_and_src.jar' but I'm unsure where I should place that jar. In the root of my library's jar? – ecc Mar 31 '14 at 17:55
  • 1
    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. – Viggo Mar 31 '14 at 21:07
  • Thanks @Viggo, I guess it's time I learn to use Maven. If you want, include that comment in your response so I can accept it. – ecc Apr 01 '14 at 08:33