Search code examples
javajakarta-eeejbcdi

Why an ejb that has another ejb as a field doesn´t update the values of this ejb that is acting as a field?


I am making my first approach to java-ee. What I am trying to achieve is next: I have written an application that collects bets prices from differents sources, I manage the collected data into a custom List class(ListEventsArquitectura) that manages the events data stored in EventoArquitectura(custom class). This EventoArquitectura class has also as fields other custom objects like BetArquitectura.

What I am testing is that this application works as a client of an Ejb sending the collected data to have it available later as a Rest webservice of the Ejb.

Now I have an ejb remote interface to modify fields of EventoArquitectura instances contained into ListEventsArquitectura, and it works but as EventoArquitectura instances have as a field instances of BetArquitectura I also created another Ejb remote interface to modify the fields of BetArquitectura and here is where I have the problem because the updates of the field BetArquitectura contained into EventoArquitectura doesn't produce any change.

I leave my code of the classes created for the tests and for the remote client.

For clarification, I am not using @Inject because it produces errors deploying to glassfish so I change the annotation to @Ejb.

@Stateful
public class ListEventsArquitectura implements ListEventsArquitecturaService{

    List<EventoArquitectura> listaDeEventos;

   @Ejb
    private EventoArquitectura eventoService;


    public ListEventsArquitectura() {
        this.listaDeEventos = new ArrayList<>();
        List<BetArquitectura> betsList = new ArrayList<>();
        //betsList.add(new BetArquitectura("betDelConstructor", "0"));
        this.listaDeEventos.add(new EventoArquitectura("evento del contructor id", "betIdDelConstructor"));
    }

    public List<EventoArquitectura> getListaDeEventos() {
        return listaDeEventos;
    }

    @Override
    public void updateListEvent(EventoArquitectura eventoActualizado){

        for(EventoArquitectura evento : this.listaDeEventos){
            if(evento.equals(eventoActualizado)){
                this.eventoService = evento;
                eventoService.updateEvent(eventoActualizado);
                return;
            }
        }
    }

    @Override
    public EventoArquitectura getEventFromList(int index) {
       return this.listaDeEventos.get(index);
    }

    @Override
    public void addEvent(EventoArquitectura evento) {
        this.listaDeEventos.add(evento);
    }

}
public interface ListEventsArquitecturaService {
    public void updateListEvent(EventoArquitectura updatedEvent);
    public EventoArquitectura getEventFromList(int index);
    public void addEvent(EventoArquitectura evento);
}
@Stateful
public class EventoArquitectura implements Serializable,EventoArquitecturaService {

    String eventId;
   // List<BetArquitectura> betsList;
    String betId;
    public EventoArquitectura() {
    }

    public EventoArquitectura(String eventId, String betId) {
        this.eventId = eventId;
        //this.betsList = betsList;
    }

    public String getEventId() {
        return eventId;
    }

    public void setEventId(String eventId) {
        this.eventId = eventId;
    }

   /* public List<BetArquitectura> getBetsList() {
        return betsList;
    }

    public void setBetsList(List<BetArquitectura> betsList) {
        this.betsList = betsList;
    }
    */

    public String getBetId() {
        return betId;
    }

    public void setBetId(String betId) {
        this.betId = betId;
    }


    @Override
    public void updateEvent(EventoArquitectura updatedEvent){
        if(!(updatedEvent.equals(this))){
            this.eventId = updatedEvent.eventId;
        }

    }

    @Override
    public boolean equals(Object obj) {
         if(!(obj instanceof EventoArquitectura)){
           return false; 
        }

        EventoArquitectura evento = (EventoArquitectura)obj;

       return evento.eventId.equals(this.eventId);
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + Objects.hashCode(this.eventId);
        return hash;
    }


}
@Remote
public interface EventoArquitecturaService {

    public void updateEvent(EventoArquitectura updatedEvent);
    public String getBetId();
    public void setBetId(String betId);

}
public class BetArquitectura implements Serializable{
    String marketId;
    String valorBet;

    public BetArquitectura(String marketId, String valorBet) {
        this.marketId = marketId;
        this.valorBet = valorBet;
    }

    public BetArquitectura() {
    }

    public String getMarketId() {
        return marketId;
    }

    public void setMarketId(String marketId) {
        this.marketId = marketId;
    }

    public String getValorBet() {
        return valorBet;
    }

    public void setValorBet(String valorBet) {
        this.valorBet = valorBet;
    }

    private void updateValor(String valorBet){
        this.valorBet = valorBet;
    }

    public void updateBet(BetArquitectura betActualizada){
        if(this.equals(betActualizada)){
            this.updateValor(betActualizada.getValorBet());
        }

    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof BetArquitectura)){
           return false; 
        }

        BetArquitectura bet = (BetArquitectura)obj;

       return bet.marketId.equals(this.marketId);
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 89 * hash + Objects.hashCode(this.marketId);
        return hash;
    }

}

And here I leave my remote client, It can change values of fields of the instances of EventoArquitectura contained in the ListEventsArquitectura, but if It doesn´t make changes into BetArquitectura object contained into each EventoArquitectura instance.

public class ClienteArquitecturaTest {

    public static void main(String[] args){


        try {
            Properties props = new Properties();
            props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
            props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
            props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
            // optional. Default localhost. Aquise cambia la IP del servidor donde esta Glassfishprops.setProperty("org.omg.CORBA.ORBInitialHost", "127.0.0.1");
            // optional. Puerto por Default 3700. Solo se necesita cambiar si el puerto no es 3700.
            //props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
            Context jndi;
            jndi = new InitialContext(props);
            ListEventsArquitecturaService listEventsService = (ListEventsArquitecturaService) jndi.lookup("java:global/ArquitecturaEJBTest/ListEventsArquitectura!com.mycompany.ejb.interfaces.ListEventsArquitecturaService");

            System.out.println("Id of the event added into constructor: " + listEventsService.getEventFromList(0).getEventId());

            EventoArquitecturaService eventoParaModificar = listEventsService.getEventFromList(0);
            eventoParaModificar.setBetId("betIdModified");

            listEventsService.addEvent(new EventoArquitectura("newEventId", "newBetId"));            



           System.out.println("Modified Bet Id: " + listEventsService.getEventFromList(0).getBetId());
            System.out.println("Added EventoArquitectura id: " + listEventsService.getEventFromList(1).getEventId());
            System.out.println("Added Bet Id: " + listEventsService.getEventFromList(1).getBetId());

        } catch (NamingException ex) {
            Logger.getLogger(ClienteArquitecturaTest.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}

And the output I get with this client, shows that I didn´t achieve to modify BetArquitectura objects, they are always null:

Id of the event added into constructor: evento del contructor id
Modified Bet Id: null
Added EventoArquitectura id: newEventId
Added Bet Id: null

Solution

  • I think your problem is that you modifiy an property of an instance which does only exists on the client side. When you call a method via a EJB client proxy, which returns an object, then you get an own instance (serialized on server side and deserialized at client side). These are two different objects, one exists on the client side and the other on the server side. Thats a common misunderstanding when working with remote ejbs.

    Try to implement a method on your EJB like this, which modifies the intended object property on ther server side.

    setIdAt(Integer idx, String id) 
    

    Then implement on the client side

     // will pass parameters to server side EJB, which modifies the object property
    service.setIdAt(0, "betIdModified");
    // Get server side modified instance and its id
    service.getElementFromList(0).getBetId();
    

    With the example you pass parameters to the server side EJB and and the object on the server side gets modfied, which you retrieve after the server side EJB has modified it. Again, you get your own instance, which is not a proxy, as I assume you expect it to be. Only the service is proxied not the objects its methods return.