Search code examples
jakarta-eejbosswildfly-10

WildFly 10: @Stateful.name property is ignored


I'm trying to put up an EJB Container on JBoss Wildfly on my local machine, and I, with some help, managed to get the container up and running, with the Remote EJB beans recognized. However, I'd like them to be named differently.

I have a NAME property in all interfaces with the desired name of the implementing bean. I put that string in the @Stateless(name = Interface.NAME).

However, the bean still gets created with the implementing class name. What should I do?

Edit: My EJB Implementation:

@Stateful(mappedName = StateService.NAME)
public class StateServiceImpl implements StateService {

private final Map<SessionId, Deque<State>> sessions;
private final List<StateChangeListener> listeners;

public StateServiceImpl() {
    this.sessions = new HashMap<>();
    this.listeners = new ArrayList<>();
}

@Override
public State getCurrentState(SessionId sessionId) {
    return sessions.get(sessionId).peek();
}

@Override
public State popCurrentState(SessionId sessionId) {
    State previousState = sessions.get(sessionId).pop();
    State currentState = sessions.get(sessionId).peek();

    StateChangeEvent event = new StateChangeEvent(previousState, currentState);
    fireStateChangeEvent(event);

    return currentState;
}

@Override
public Deque<State> getStateHistory(SessionId sessionId) {
    return new LinkedList<>(sessions.get(sessionId));
}

@Override
public void updateState(SessionId sessionId, State state) {
    State previousState = sessions.get(sessionId).peek();

    if (!sessions.containsKey(sessionId)) {
        sessions.put(sessionId, new LinkedList<>());
    }

    sessions.get(sessionId).push(state);

    StateChangeEvent event = new StateChangeEvent(previousState, state);
    fireStateChangeEvent(event);
}

@Override
public void addStateChangeListener(StateChangeListener listener) {
    listeners.add(listener);
}

@Override
public void removeStateChangeListener(StateChangeListener listener) {
    listeners.remove(listener);
}

protected void fireStateChangeEvent(StateChangeEvent event) {
    listeners.forEach(listener -> listener.stateChanged(event));
}
}

My Interface:

/**
 * Service interface to manage state changes on the server-side
 */
@Remote
public interface StateService {

    String NAME = "StateService";

    /**
     * returns the most recent state stored for the given session id
     */
    State getCurrentState(SessionId sessionId);

    /**
     * removes the last entry of session from the queue, returning the one before
     */
    State popCurrentState(SessionId sessionId);

    /**
     * returns the whole history of a given client
     */
    Deque<State> getStateHistory(SessionId sessionId);

    /**
     * adds a new session to the stack
     *
     * @param sessionId the client the state is updated for
     * @param state     the updated state
     */
    void updateState(SessionId sessionId, State state);

    void addStateChangeListener(StateChangeListener listener);

    void removeStateChangeListener(StateChangeListener listener);

    interface StateChangeListener {
        void stateChanged(StateChangeEvent event);
    }

    @AllArgsConstructor
    @Getter
    class StateChangeEvent {
        private final State previousState;
        private final State nextState;
    }
}

These are the bindings:

[INFO] [talledLocalContainer]   java:global/web-be/web-impl-0.0.1-SNAPSHOT/MenuServiceImpl!io.ropi.fiveshelly.services.MenuService
[INFO] [talledLocalContainer]   java:app/web-impl-0.0.1-SNAPSHOT/MenuServiceImpl!io.ropi.fiveshelly.services.MenuService
[INFO] [talledLocalContainer]   java:module/MenuServiceImpl!io.ropi.fiveshelly.services.MenuService
[INFO] [talledLocalContainer]   java:global/web-be/web-impl-0.0.1-SNAPSHOT/MenuServiceImpl
[INFO] [talledLocalContainer]   java:app/web-impl-0.0.1-SNAPSHOT/MenuServiceImpl
[INFO] [talledLocalContainer]   java:module/MenuServiceImpl

Thanks in advance


Solution

  • I don't know if you can change the name of the class itself, but as an example you can use the name of the published JNDI (Depends is my project's name):

    java:global/Depends/NameDesired!MyClassName
    java:app/Depends/NameDesired!MyClassName
    java:module/NameDesired!MyClassName
    java:global/Depends/NameDesired
    java:app/Depends/NameDesired
    java:module/NameDesired
    

    The class is this:

    import javax.ejb.Stateless;
    
    @Stateless(name="NameDesired")
    public class MyClassName { 
        public void doThing() {
            System.out.println("Doing some work...");
        }
    } 
    

    Then you can use like:

    //I'm using here the fourth line of the JNDI, just using the name I want:
    MyClassName example = (MyClassName) (new InitialContext().lookup("java:global/Depends/NameDesired"));
    

    or even

    @EJB(beanName="NameDesired")
    private MyClassName example;
    

    Note that you are using the correct annotation already @Stateless(name=""). As we talked in chat, you can set the name you want using a String. Even more you can lookup using Environment Variable and how to Configure it, but in your case, I don't know if worth it.