Kawu
Kawu

Reputation: 14003

Overridden @PostConstruct called twice on CDI view-scoped bean (Weld, Seam 3)

We're having problems with duplicate @PostConstruct calls on a base class hierarchy.

Here's the base class first:

public abstract class AbstractManager<T> implements Serializable
{
    private List<T> entities;

    @PostConstruct // when annotated with @PostConstruct this method is called even if overridden in sub class
    public void init()
    {
        System.out.println( AbstractManager.class.getSimpleName() + " @PostConstruct on " + this.getClass().getSimpleName() + "!" );
    }

    protected abstract List<T> getDbEntities();

    public List<T> getEntities()
    {
        if ( this.entities == null )
        {
            this.entities = this.getDbEntities();
        }

        return this.entities;
    }

    public void setEntities( List<T> entities )
    {
        this.entities = entities;
    }

    public void clearEntities()
    {
        this.entities = null;
    }
}

Here's the concrete sub class (notice how init() is overridden to call super.init()):

@Named
@ViewScoped
public class PseudoEntityManager extends AbstractManager<PseudoEntity>
{
    private static final long serialVersionUID = 1L;

    @Override
    @PostConstruct
    public void init()
    {
        super.init();
    }

    ...
}

When some (unshown) page is rendered, the pseudoEntityManager bean is instantiated, however @PostConstruct is called twice. This is the output:

INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: New list of pseudo DB entities!

When commenting the overriding init() method in the concrete sub class so that there's only one @PostConstruct method from the super class, the following output is generated:

INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: New list of pseudo DB entities!

Q:

What's the correct behavior according to CDI specification now? (references anybody?)

Notes:

I also found this mailing list conversation while researching:

http://list-archives.org/2012/10/11/cdi-dev-lists-jboss-org/postconstruct-on-inherited-class/f/4426568582

In the conversation, some gurus tend to say "only the @PostConstruct method on the sub class should be called". If you read closely, there's a link to a Weld bug that's said to be resolved since Weld 1.1.5:

https://issues.jboss.org/browse/WELD-1225

Has this really been fixed? According to the output I get, it's not.

Environment: Weld 1.1.8 along with Seam 3 to get the CDI @ViewScoped working correctly (on GlassFish 3.1.2).

Upvotes: 0

Views: 3014

Answers (2)

This is a Workaround answer.

With the Bug mentioned both @PostConstruct annotation are considered, and their logic code is executed.

  1. using @Override will execute the post on the superclass which is overriden by the subclass
  2. then the post on the subclass will be executed as well.

to workaround this is possible to do as following:

  • define a new signature and mark it @PostConstruct
  • override the superclass method marked as @PostConstruct, but dont put @PostConstruct Annotation, just the @Override, and implement it empty.

As result you will have only executed the code marked @PostConstruct on your subclass:

@Specializes
@ViewAccessScoped
public class BaseBean extends SubBean {

@PostConstruct
public void postConstructExtension() {
    LOGGER.info("POST CALLED ON SPECIALIZED CLASS" + this.getClass().getSimpleName());
}

@Override
public void postConstruct() {
    LOGGER.info("OVERRIDDEN POST CALLED ON SPECIALIZED CLASS" + this.getClass().getSimpleName());
}

}

Upvotes: 1

John Ament
John Ament

Reputation: 11723

Yes, it's been fixed. Unfortunately, it's only fixed in the Weld 2.0 release line. Sometimes these bugs get back ported, but unfortunately I doubt this one will end up being resolved in the maintenance releases.

Upvotes: 1

Related Questions