简体   繁体   中英

How can I access property value from a managed bean in a java class?

I was having the idea to set a global property for session eg "god-mode" so during the session a person can see more than average (just for development purpose) eg

<managed-bean>
        <managed-bean-name>appBean</managed-bean-name>
        <managed-bean-class>se.corp.app.package.ApplicationBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
        <managed-property>
            <property-name>godmode</property-name>
            <value>true</value>
            <property-class>java.lang.Boolean</property-class>
        </managed-property>
    </managed-bean>

But how can I access the property set from within another java class?

Add a getInstance() method to your ApplicationBean class:

public static ApplicationBean get() {
    return (ApplicationBean) resolveVariable("appBean");
}

I am using an utility method for resolving the bean variable. This method is part of the newer extension library as ExtLibUtil.resolveVariable(name) and available here:

public static Object resolveVariable(String variable) {
    return FacesContext.getCurrentInstance().getApplication().getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(), variable);
}

You can then access the bean from another class like this:

ApplicationBean appBean = ApplicationBean.get();

You can then access all your public properties and methods in ApplicationBean.

You can go 2 ways about this: one easy, the other one more in line with the general JSF philosophy. In other words it's a matter of personal integrity to technology principles :D

The easy one is the one illustrated by Per Henrik Lausten. However it's flawed in a way. It isn't really environment neutral/agnostic. It doesn't mean it's a problem but if you want to redistribute your bean you are forced, and are forcing, you, your implementor, to go by the bean name of your choosing - eg appBean

Now I don't want to overcomplicate things but a more flexible approach would be the following:

 <managed-bean>
      <managed-bean-name>appBean</managed-bean-name>
      <managed-bean-class>bean.ApplicationBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      <managed-property>
           <property-name>name</property-name>
           <value>appBean</value>
      </managed-property>
 </managed-bean>

The bean:

public class ApplicationBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final String DEFAULT_NAME = "appBean";

    private String name;
    private boolean godMode;

    public void setName(String name) {
        this.name = name;
    }

    public void setGodMode(boolean godMode) {
        this.godMode = godMode;
    }

    public boolean isGodMode() {
        return godMode;
    }

    // Your other logic here

    public static ApplicationBean getInstance(FacesContext facesContext) {
        return (ApplicationBean) Helper.resolveVariable(facesContext, name != null ? name : DEFAULT_NAME);
    }

}

With the above approach the bean can be deployed anywhere and if necessary you can define a different name - managed-bean-name and the property value MUST match. Otherwise you omit the name property in the faces-config.xml while setting the managed-bean-name exactly as it appears in the DEFAULT_NAME java class property.

The "philosophical" way instead is the one of leveraging the attribute injection. It all depends on how often you find yourself needing a particular bean across all your beans. But see the example first:

 <managed-bean>
      <managed-bean-name>appBean</managed-bean-name>
      <managed-bean-class>bean.ApplicationBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      <managed-property>
           <property-name>godMode</property-name>
           <value>true</value>
                <property-class>java.lang.Boolean</property-class>
      </managed-property>
 </managed-bean>

 <managed-bean>
      <managed-bean-name>myOtherBean</managed-bean-name>
      <managed-bean-class>bean.MyOtherBean</managed-bean-class>
      <managed-bean-scope>view</managed-bean-scope>
      <managed-property>
           <property-name>app</property-name>
           <value>#{appBean}</value>
      </managed-property>
 </managed-bean>

The other bean class:

public class MyOtherBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private ApplicationBean app;

    public void setApp(ApplicationBean app) {
        this.app = app;
    }

    public void doSomething() {
        // App is already here
        // no need to resolve it
        if (app.isGodMode()) {
            //do something;
        }
    }
}

I personally use both approaches, although I prefer this last approach. Theres a catch though: you can only inject beans that share the same scope or that outlive the scope of the bean you are injecting them in.

app into session: YES

session into view: YES

view into app: NO

request into view: NO

All managed beans, dataContext, datasources etc are allocated a reference and that's available for the lifecycle of the managed bean etc. So if a dominoDocument with variable name "myXPageDocument" is defined at the XPage, you can use that "myXPageDocument" identifier throughout the XPage or any custom control inserted into the XPage or code called from the XPage, to access it. (If the same variable name is used, you might just get the "nearest" one.) Same also for managed beans. If you have a viewScoped bean, anywhere on the XPage or custom control inserted into the XPage or code called from the XPage, you can access it.

To access any of those, just pass the variable name to ExtLibUtil.resolve(appBean) . Since ExtLib 9.0.1 v15, I think, or Domino 9.0.1 FP8 it can just take one parameter, the variable name. This calls the VariableResolver which accesses all implicit objects (beans, session , etc) and scopes until it finds something with the variable name passed in.

I've interpreted your question differently from Per and Paul (Hi Per, hi Paul, long time no see!) and I think you want to be able to access the managed Bean within your XPage.

You can access any property of a managed bean with the help of Expression Language. IBM provides little documentation, but it's awesome and will really help you keep your code where it should be, ie in Java classes. Here's the doc for Expression Language:

https://docs.oracle.com/javaee/6/tutorial/doc/gjddd.html

Once the managed bean has been configured in faces-config

<managed-bean>
<managed-bean-name>TableOfContents</managed-bean-name>
<managed-bean-class>ch.magerman.zhpedia.tableofcontents.TableOfContents</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>

you can then access its methods in the XPages just by referring to its name

eg

<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:xc="http://www.ibm.com/xsp/custom"
    style="display:block;"
    beforePageLoad="#{TableOfContents.beforePageLoad}">

or also its values:

<xp:repeat
    id="repeatfirstlevelnodes"
    rows="200"
    value="#{TableOfContents.root.children}"
    var="firstlevelnode"
    styleClass="NavLeft">

One gotcha is the capitalisation. In this example my getter for .root looks like this in Java:

public Node getRoot() {
    return rootNode;
}

and to access this, you need to remove the 'get' prefix and change the capital R to lowercase r.

I hope this helps!

Hm, all the answers (yet) copy the same mistake you introduced in your question: by setting the property by faces-config ALL users will enter god mode...

My two cents: for the purpose you have in mind we use role in database ACL called "Debug". But "GodMode" will do just fine. Anywhere in your code you can ask for user's ACL roles and check for debug role. Typical use case is to show/hide components helping with debug/development.

https://lostinxpages.com/2014/01/06/finding-user-roles-in-xpages/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM