@ApplicationScoped beans get constructed more than once
I have two managed Java beans:
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.ws.rs.Path;
@Path("/sync")
@ManagedBean(name="syncService", eager=true)
@ApplicationScoped
public class SyncService {
@ManagedProperty(value="#{ldapDirectoryAccess}")
private DirectoryAccess directoryAccess;
public void setDirectoryAccess(DirectoryAccess directoryAccess) {
System.out.println("SyncService.setDirectoryAccess()");
this.directoryAccess = directoryAccess;
}
public SyncService() {
System.out.println("SyncService() - constructed: " + this);
}
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
...
}
@ManagedBean(name="ldapDirectoryAccess", eager=true)
@ApplicationScoped
public class LdapDirectoryAccess implements DirectoryAccess {
public LdapDirectoryAccess() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
...
}
When I deploy the application in Tomcat, I get the following output in catalina.out
:
SyncService() - constructed: ...SyncService@705ebb4d
...
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@3c1fd5aa
SyncService.setDirectoryAccess()
DirectoryAccess injected: ...LdapDirectoryAccess@3c1fd5aa in:
...SyncService@705ebb4d
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@59d6a4d1
So, first an instance of each bean is constructed as expected, and the second bean is injected into the first. But then, another instance of the second bean class is created. How is this possible? In this tutorial I found the following:
@ApplicationScoped
Bean lives as long as the web application lives. It gets created upon
the first HTTP request involving this bean in the application (or when
the web application starts up and the eager=true attribute is set in
@ManagedBean) and gets destroyed when the web application shuts down.
So I would expected that one instance of each bean is created when the application is started, and that both instances are destroyed when the application is shut down. But LdapDirectoryAccess
is constructed twice.
Moreover, when I open the page that is served by SyncService
I see:
SyncService() - constructed: ... SyncService@1cb4a09c
so a second instance of SyncService
is built as well, and I cannot understand why. Also, no directoryAccess
property is injected this time, and the service throws a null pointer exception.
This means that the first instance of SyncService
is built correctly, but then
- A second instance of
SyncService
is created (why?) - No
LdapDirectoryAccess
is injected into it (why?) - This second instance of
SyncService
is used to serve the call to my REST API. Why this instance and not the first one that was created?
I have looked at this question and its answers, however:
- I am using Mojarra 2.2.18
- My application's
web.xml
does not contain any tag mentioningcom.sun.faces.config.ConfigureListener
So I after several hours investigation I am completely out of ideas. Do you have any hints?
jsf dependency-injection managed-bean
add a comment |
I have two managed Java beans:
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.ws.rs.Path;
@Path("/sync")
@ManagedBean(name="syncService", eager=true)
@ApplicationScoped
public class SyncService {
@ManagedProperty(value="#{ldapDirectoryAccess}")
private DirectoryAccess directoryAccess;
public void setDirectoryAccess(DirectoryAccess directoryAccess) {
System.out.println("SyncService.setDirectoryAccess()");
this.directoryAccess = directoryAccess;
}
public SyncService() {
System.out.println("SyncService() - constructed: " + this);
}
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
...
}
@ManagedBean(name="ldapDirectoryAccess", eager=true)
@ApplicationScoped
public class LdapDirectoryAccess implements DirectoryAccess {
public LdapDirectoryAccess() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
...
}
When I deploy the application in Tomcat, I get the following output in catalina.out
:
SyncService() - constructed: ...SyncService@705ebb4d
...
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@3c1fd5aa
SyncService.setDirectoryAccess()
DirectoryAccess injected: ...LdapDirectoryAccess@3c1fd5aa in:
...SyncService@705ebb4d
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@59d6a4d1
So, first an instance of each bean is constructed as expected, and the second bean is injected into the first. But then, another instance of the second bean class is created. How is this possible? In this tutorial I found the following:
@ApplicationScoped
Bean lives as long as the web application lives. It gets created upon
the first HTTP request involving this bean in the application (or when
the web application starts up and the eager=true attribute is set in
@ManagedBean) and gets destroyed when the web application shuts down.
So I would expected that one instance of each bean is created when the application is started, and that both instances are destroyed when the application is shut down. But LdapDirectoryAccess
is constructed twice.
Moreover, when I open the page that is served by SyncService
I see:
SyncService() - constructed: ... SyncService@1cb4a09c
so a second instance of SyncService
is built as well, and I cannot understand why. Also, no directoryAccess
property is injected this time, and the service throws a null pointer exception.
This means that the first instance of SyncService
is built correctly, but then
- A second instance of
SyncService
is created (why?) - No
LdapDirectoryAccess
is injected into it (why?) - This second instance of
SyncService
is used to serve the call to my REST API. Why this instance and not the first one that was created?
I have looked at this question and its answers, however:
- I am using Mojarra 2.2.18
- My application's
web.xml
does not contain any tag mentioningcom.sun.faces.config.ConfigureListener
So I after several hours investigation I am completely out of ideas. Do you have any hints?
jsf dependency-injection managed-bean
add a comment |
I have two managed Java beans:
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.ws.rs.Path;
@Path("/sync")
@ManagedBean(name="syncService", eager=true)
@ApplicationScoped
public class SyncService {
@ManagedProperty(value="#{ldapDirectoryAccess}")
private DirectoryAccess directoryAccess;
public void setDirectoryAccess(DirectoryAccess directoryAccess) {
System.out.println("SyncService.setDirectoryAccess()");
this.directoryAccess = directoryAccess;
}
public SyncService() {
System.out.println("SyncService() - constructed: " + this);
}
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
...
}
@ManagedBean(name="ldapDirectoryAccess", eager=true)
@ApplicationScoped
public class LdapDirectoryAccess implements DirectoryAccess {
public LdapDirectoryAccess() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
...
}
When I deploy the application in Tomcat, I get the following output in catalina.out
:
SyncService() - constructed: ...SyncService@705ebb4d
...
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@3c1fd5aa
SyncService.setDirectoryAccess()
DirectoryAccess injected: ...LdapDirectoryAccess@3c1fd5aa in:
...SyncService@705ebb4d
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@59d6a4d1
So, first an instance of each bean is constructed as expected, and the second bean is injected into the first. But then, another instance of the second bean class is created. How is this possible? In this tutorial I found the following:
@ApplicationScoped
Bean lives as long as the web application lives. It gets created upon
the first HTTP request involving this bean in the application (or when
the web application starts up and the eager=true attribute is set in
@ManagedBean) and gets destroyed when the web application shuts down.
So I would expected that one instance of each bean is created when the application is started, and that both instances are destroyed when the application is shut down. But LdapDirectoryAccess
is constructed twice.
Moreover, when I open the page that is served by SyncService
I see:
SyncService() - constructed: ... SyncService@1cb4a09c
so a second instance of SyncService
is built as well, and I cannot understand why. Also, no directoryAccess
property is injected this time, and the service throws a null pointer exception.
This means that the first instance of SyncService
is built correctly, but then
- A second instance of
SyncService
is created (why?) - No
LdapDirectoryAccess
is injected into it (why?) - This second instance of
SyncService
is used to serve the call to my REST API. Why this instance and not the first one that was created?
I have looked at this question and its answers, however:
- I am using Mojarra 2.2.18
- My application's
web.xml
does not contain any tag mentioningcom.sun.faces.config.ConfigureListener
So I after several hours investigation I am completely out of ideas. Do you have any hints?
jsf dependency-injection managed-bean
I have two managed Java beans:
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.ws.rs.Path;
@Path("/sync")
@ManagedBean(name="syncService", eager=true)
@ApplicationScoped
public class SyncService {
@ManagedProperty(value="#{ldapDirectoryAccess}")
private DirectoryAccess directoryAccess;
public void setDirectoryAccess(DirectoryAccess directoryAccess) {
System.out.println("SyncService.setDirectoryAccess()");
this.directoryAccess = directoryAccess;
}
public SyncService() {
System.out.println("SyncService() - constructed: " + this);
}
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
...
}
@ManagedBean(name="ldapDirectoryAccess", eager=true)
@ApplicationScoped
public class LdapDirectoryAccess implements DirectoryAccess {
public LdapDirectoryAccess() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
...
}
When I deploy the application in Tomcat, I get the following output in catalina.out
:
SyncService() - constructed: ...SyncService@705ebb4d
...
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@3c1fd5aa
SyncService.setDirectoryAccess()
DirectoryAccess injected: ...LdapDirectoryAccess@3c1fd5aa in:
...SyncService@705ebb4d
LdapDirectoryAccess constructed: ...LdapDirectoryAccess@59d6a4d1
So, first an instance of each bean is constructed as expected, and the second bean is injected into the first. But then, another instance of the second bean class is created. How is this possible? In this tutorial I found the following:
@ApplicationScoped
Bean lives as long as the web application lives. It gets created upon
the first HTTP request involving this bean in the application (or when
the web application starts up and the eager=true attribute is set in
@ManagedBean) and gets destroyed when the web application shuts down.
So I would expected that one instance of each bean is created when the application is started, and that both instances are destroyed when the application is shut down. But LdapDirectoryAccess
is constructed twice.
Moreover, when I open the page that is served by SyncService
I see:
SyncService() - constructed: ... SyncService@1cb4a09c
so a second instance of SyncService
is built as well, and I cannot understand why. Also, no directoryAccess
property is injected this time, and the service throws a null pointer exception.
This means that the first instance of SyncService
is built correctly, but then
- A second instance of
SyncService
is created (why?) - No
LdapDirectoryAccess
is injected into it (why?) - This second instance of
SyncService
is used to serve the call to my REST API. Why this instance and not the first one that was created?
I have looked at this question and its answers, however:
- I am using Mojarra 2.2.18
- My application's
web.xml
does not contain any tag mentioningcom.sun.faces.config.ConfigureListener
So I after several hours investigation I am completely out of ideas. Do you have any hints?
jsf dependency-injection managed-bean
jsf dependency-injection managed-bean
edited Nov 19 '18 at 14:44
Giorgio
asked Nov 19 '18 at 14:02
GiorgioGiorgio
2,66252857
2,66252857
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
A second instance of
SyncService
is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
- JAX-RS, via
@Path
- JSF, via
@ManagedBean
So, in effects, you have one instance of SyncService
which is managed by JAX-RS, and you have another instance of SyncService
which is managed by JSF, and only in this instance, the also JSF-specific @ManagedProperty
is recognized. JAX-RS doesn't understand the @ManagedProperty
and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService
into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess
to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's @javax.enterprise.context.ApplicationScoped
. In legacy Java EE 6/7, you could abuse EJB's @javax.ejb.Singleton
for that.
Given that you're still using the deprecated @ManagedBean
instead of its replacement @Named
, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
@PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
@Path("/sync")
public class SyncResource {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SyncBacking {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService
to eagerly initialize during server's startup, add the @javax.ejb.Startup
annotation.
See also:
- Inject an EJB into JAX-RS (RESTful service)
- JSF Controller, Service and DAO
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
How to choose the right bean scope?
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to useJSF
and I did not know that the@Path
annotation was part of another framework. Also, I did not know that@ManagedBean
was deprecated since searching for dependency injection inJSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.
– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53376320%2fapplicationscoped-beans-get-constructed-more-than-once%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
A second instance of
SyncService
is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
- JAX-RS, via
@Path
- JSF, via
@ManagedBean
So, in effects, you have one instance of SyncService
which is managed by JAX-RS, and you have another instance of SyncService
which is managed by JSF, and only in this instance, the also JSF-specific @ManagedProperty
is recognized. JAX-RS doesn't understand the @ManagedProperty
and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService
into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess
to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's @javax.enterprise.context.ApplicationScoped
. In legacy Java EE 6/7, you could abuse EJB's @javax.ejb.Singleton
for that.
Given that you're still using the deprecated @ManagedBean
instead of its replacement @Named
, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
@PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
@Path("/sync")
public class SyncResource {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SyncBacking {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService
to eagerly initialize during server's startup, add the @javax.ejb.Startup
annotation.
See also:
- Inject an EJB into JAX-RS (RESTful service)
- JSF Controller, Service and DAO
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
How to choose the right bean scope?
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to useJSF
and I did not know that the@Path
annotation was part of another framework. Also, I did not know that@ManagedBean
was deprecated since searching for dependency injection inJSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.
– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
add a comment |
A second instance of
SyncService
is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
- JAX-RS, via
@Path
- JSF, via
@ManagedBean
So, in effects, you have one instance of SyncService
which is managed by JAX-RS, and you have another instance of SyncService
which is managed by JSF, and only in this instance, the also JSF-specific @ManagedProperty
is recognized. JAX-RS doesn't understand the @ManagedProperty
and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService
into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess
to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's @javax.enterprise.context.ApplicationScoped
. In legacy Java EE 6/7, you could abuse EJB's @javax.ejb.Singleton
for that.
Given that you're still using the deprecated @ManagedBean
instead of its replacement @Named
, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
@PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
@Path("/sync")
public class SyncResource {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SyncBacking {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService
to eagerly initialize during server's startup, add the @javax.ejb.Startup
annotation.
See also:
- Inject an EJB into JAX-RS (RESTful service)
- JSF Controller, Service and DAO
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
How to choose the right bean scope?
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to useJSF
and I did not know that the@Path
annotation was part of another framework. Also, I did not know that@ManagedBean
was deprecated since searching for dependency injection inJSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.
– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
add a comment |
A second instance of
SyncService
is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
- JAX-RS, via
@Path
- JSF, via
@ManagedBean
So, in effects, you have one instance of SyncService
which is managed by JAX-RS, and you have another instance of SyncService
which is managed by JSF, and only in this instance, the also JSF-specific @ManagedProperty
is recognized. JAX-RS doesn't understand the @ManagedProperty
and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService
into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess
to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's @javax.enterprise.context.ApplicationScoped
. In legacy Java EE 6/7, you could abuse EJB's @javax.ejb.Singleton
for that.
Given that you're still using the deprecated @ManagedBean
instead of its replacement @Named
, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
@PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
@Path("/sync")
public class SyncResource {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SyncBacking {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService
to eagerly initialize during server's startup, add the @javax.ejb.Startup
annotation.
See also:
- Inject an EJB into JAX-RS (RESTful service)
- JSF Controller, Service and DAO
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
How to choose the right bean scope?
A second instance of
SyncService
is created (why?)
Because two different frameworks, completely unaware of each other, are being instructed to manage (instantiate and use) it.
- JAX-RS, via
@Path
- JSF, via
@ManagedBean
So, in effects, you have one instance of SyncService
which is managed by JAX-RS, and you have another instance of SyncService
which is managed by JSF, and only in this instance, the also JSF-specific @ManagedProperty
is recognized. JAX-RS doesn't understand the @ManagedProperty
and thus does nothing with it.
Basically, you're here tight-coupling a JAX-RS resource and a JSF managed bean in the very same class. Tight-coupling is a bad programming practice. You need to split out SyncService
into one independent JAX-RS resource and one independent JSF managed bean. And you'd need to convert the LdapDirectoryAccess
to use another bean management framework which is recognized by both JAX-RS and JSF, so that a single instance can be injected in both. In modern Java EE 8, that would be a bean managed by CDI's @javax.enterprise.context.ApplicationScoped
. In legacy Java EE 6/7, you could abuse EJB's @javax.ejb.Singleton
for that.
Given that you're still using the deprecated @ManagedBean
instead of its replacement @Named
, I'll assume that you're still on legacy Java EE, so I'll show only the EJB approach.
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
@Singleton
public class LdapDirectoryAccessService implements DirectoryAccess {
@PostConstruct
public void init() {
System.out.println("LdapDirectoryAccess constructed: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ws.rs.Path;
@Path("/sync")
public class SyncResource {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SyncBacking {
@EJB
private DirectoryAccess directoryAccess;
@PostConstruct
public void init() {
System.out.println("DirectoryAccess injected: " + directoryAccess + " in: " + this);
}
}
Note that being able to inject an EJB in a JAX-RS resource might require additional configuration in Java EE 6/7, for that see the first link of the list below. And, in case you want to LdapDirectoryAccessService
to eagerly initialize during server's startup, add the @javax.ejb.Startup
annotation.
See also:
- Inject an EJB into JAX-RS (RESTful service)
- JSF Controller, Service and DAO
- Backing beans (@ManagedBean) or CDI Beans (@Named)?
How to choose the right bean scope?
edited Nov 19 '18 at 18:00
answered Nov 19 '18 at 17:46
BalusCBalusC
845k29731313211
845k29731313211
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to useJSF
and I did not know that the@Path
annotation was part of another framework. Also, I did not know that@ManagedBean
was deprecated since searching for dependency injection inJSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.
– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
add a comment |
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to useJSF
and I did not know that the@Path
annotation was part of another framework. Also, I did not know that@ManagedBean
was deprecated since searching for dependency injection inJSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.
– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to use
JSF
and I did not know that the @Path
annotation was part of another framework. Also, I did not know that @ManagedBean
was deprecated since searching for dependency injection in JSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.– Giorgio
Nov 20 '18 at 6:36
Thanks for the thorough explanation. We are working on a new project and I am learning the technologies along the way. We have been advised to use
JSF
and I did not know that the @Path
annotation was part of another framework. Also, I did not know that @ManagedBean
was deprecated since searching for dependency injection in JSF
I mostly found examples using this annotation. Anyway, thanks for the explanation and all the links: I will try to pick one framework and use it consistently.– Giorgio
Nov 20 '18 at 6:36
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@Giorgio: Google does a very bad job in this regard since if everybody keeps clicking on only articles, they keep getting higher in searchengines. I more and more try to find a common authoritive human maintained site (like e.g. jsf.zeef.com) and use that. Yes for that I use google but look for recent (version wise and date wise) links) I do that for other interesting subjects too like solar power etc...
– Kukeltje
Nov 20 '18 at 10:06
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
@BalusC Can i have your email ?
– Pie
Dec 8 '18 at 5:36
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53376320%2fapplicationscoped-beans-get-constructed-more-than-once%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown