Mostrando entradas con la etiqueta WELD. Mostrar todas las entradas
Mostrando entradas con la etiqueta WELD. Mostrar todas las entradas

viernes, 18 de agosto de 2017

JEE & JSF 6th Part: WELD selecting the injected beans programmatically

0. Introduction


To show formatted text Hilite is used

I can not conceive CDI without facilities to inject dependencies into at runtime.


I have seen these interesting related two questions at StackOverflow (the first from several participants and the second from Harald Wellmann)

This is a little tricky post so, let's try to understand the steps followed to achieve this goal:


  1. Create the main interface whose method should be implemented by the candidate classes
  2. Create an annotation (interface) with a parameter to distinguish classes that use this annotation
  3. Create the classes that implement the main interface and are annotated with the previous annotation with different parameters (in this post two classes are created)
  4. Create a tool class that implements the annotation interface used for managing the parameters of the annotation interface (this is the first tricky step)
  5. Use the type Instance<main interface> to retrieve all implementations of the main interface (this is the second tricky step)
  6. Use the method "select" from the Instance<main interface> to retrieve the desired injection class (passing the parameter of the annotation assigned in the class)

As mentioned in the previous post related to creating a menu programmatically our goal is to read the tree structure of the menu from different sources. In that post, this configuration was read from a file that was located in a relative path from src/main/resources folder by means of a class, now, let's create another class to locate and read this file by means of the absolute path of the file. Both classes will implement the same interface.

The way to select one or the other class is by means of a property "menuBeanReaderType" in the file application.properties. The way to retrieve properties was explained in the previous post for accessing properties


1. Creating the main interface


This interface is IMenuBeanReader 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package org.ximodante.jsf.menu;

import java.io.IOException;
import org.primefaces.model.menu.MenuModel;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

/**
 * Interface for reading info to build a menu.
 * @author Ximno Dante
 *
 */
public interface IMenuBeanReader {
 public void readMenu  (String source, MenuModel menuModel)
  throws JsonParseException, JsonMappingException, IOException, MenuJsfException;
}

The methid readMenu must be implemented by our classes.


2. The annotation (interface)


The annotation is ImenuBeanReaderType

This annotation has a parameter "type" that should distinguish the classes that implements the main interface (IMenuBeanReader)



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.ximodante.jsf.menu;


import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

/**
 * For distinguishing different classes that implements the IMenuBeanReader interface
 * @author Ximo Dante
 *
 */
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface IMenuBeanReaderType {
 
    String type() default "MenuBeanReaderJSONRelativePath";
}

NOTE: As it can be seen, the default value of type is MenuBeanReaderJSONRelativePath that is coincident with the name of a class that we will create later. This coincidence IS NOT NECESSARY the value of type paramenter could have been for instance "option 1".


3. The classes to be injected

Two classes have been created:

  1. MenuBeanReaderJSONRelativePath
  2. MenuBeanReaderJSONAbsolutePath
It is important to see that these two classes:

  • Implement IMenuBeanReader interface
  • Have been annotated with @IMenuBeanReaderType and have different types (for simplicity the name of each class has been used, but not necessarily)
  • Only the first class has the annotation @Default (it is recommended)
  • Annotations @Named and their scopes have been applied.


Let's see MenuBeanReaderJSONRelativePath 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.ximodante.jsf.menu;

import java.io.IOException;
import java.util.Map;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Named;

import org.primefaces.model.menu.MenuModel;
import org.ximodante.utils.json.JsonUtils;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

@Named
@ApplicationScoped
@Default
@IMenuBeanReaderType(type="MenuBeanReaderJSONRelativePath")
public class MenuBeanReaderJSONRelativePath implements IMenuBeanReader {
    
 /**
  * Reads the menu from a JSON object as a Map where the source (file name) is relative to src/main/resource folder
  * @param fileName
  * @param menu
  * @throws JsonParseException
  * @throws JsonMappingException
  * @throws IOException
  * @throws MenuJsfException
  */
 
 @Override
 public void readMenu(String source, MenuModel menuModel)
  throws JsonParseException, JsonMappingException, IOException, MenuJsfException {
  
  Map<String,Object> map=JsonUtils.readMap(true, source );

  MenuFromMap.getMenuFromMap(map, menuModel, null, 0);
  
 }
}

The other one MenuBeanReaderJSONAbsolutePath is



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package org.ximodante.jsf.menu;

import java.io.IOException;
import java.util.Map;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

import org.primefaces.model.menu.MenuModel;
import org.ximodante.utils.json.JsonUtils;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

@Named
@ApplicationScoped
@IMenuBeanReaderType(type="MenuBeanReaderJSONAbsolutePath")
public class MenuBeanReaderJSONAbsolutePath implements IMenuBeanReader {
    
 /**
  * Reads the menu from a JSON object as a Map where the source (file name) is an absolute path
  * @param fileName
  * @param menu
  * @throws JsonParseException
  * @throws JsonMappingException
  * @throws IOException
  * @throws MenuJsfException
  */
 
 @Override
 public void readMenu(String source, MenuModel menuModel)
  throws JsonParseException, JsonMappingException, IOException, MenuJsfException {
  
  Map<String,Object> map=JsonUtils.readMap(false, source );
    
  MenuFromMap.getMenuFromMap(map, menuModel, null, 0);
  
 }
} 

You can think that it is disproportionate the fact of creating a new class that is practically the same and this could be done adding a new boolean parameter to the readMenu method for accepting relative or absolute paths, but this is a learning example.

The application scoped is used as a singleton.


3. Creating the tool class

The purpose of this tool class is managing the parameter (type) of the annotation so that we can extract the desired dependency from all the possible candidates that implements the main interface.

This class is MenuBeanReaderTypeDescription 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.ximodante.jsf.menu;

import javax.enterprise.util.AnnotationLiteral;

/**
 * Class that is a tool to manage the paramemeter "type" from the Annotation IMenuBeanReaderType so that
 * the desired candidate class for injection is selected
 * 
 * @see https://stackoverflow.com/questions/33583032/dynamically-injecting-instances-via-cdi
 * @see https://stackoverflow.com/questions/24798529/how-to-programmatically-inject-a-java-cdi-managed-bean-into-a-local-variable-in
 * 
 * @author Ximo Dante
 *
 */
public class MenuBeanReaderTypeDescriptor extends AnnotationLiteral<IMenuBeanReaderType> implements IMenuBeanReaderType{
 private static final long serialVersionUID = 1L;
 
 private String type;
    
 public MenuBeanReaderTypeDescriptor(String type) {
        this.type = type;
    }
 

 @Override
    public String type() {
         return type;
    }
}


4. Using the injection into a bean

Let's use the MenuBean class from a former post about programmatic menu

Important points:

  1. In the property file, the property menuReaderTypeKey contains the parameter of the annotation IMenuBeanReaderType that chooses the class to be injected (in this case the value is "MenuBeanReaderJSONRelativePath")
  2. The singleton property reader is injected in the bean (the attribute appProps)
  3. The injected Instance<IMenuBeanReader> contains registration of all classes that implements the interface IMenuBeanReader. 
  4. By means of "select" method of the Instance<interface>  object we can retrive the desired injected class passing the parameter (type) of the annotation  




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import javax.inject.Named;

import org.primefaces.model.menu.DefaultMenuModel;
import org.primefaces.model.menu.MenuModel;
import org.ximodante.utils.property.ApplicationProperties;

import lombok.Getter;


/**
 * Implements the menu structure as a bean
 * If a bean does not implements Serializable, Tomcat crashes
 * MenuModel is the attribute to implement the men structure
 * initialMenuConfig is the name of the file to read the initial menu structure
 * 
 * @author Ximo Dante
 *
 */
@Named
@ViewScoped
public class MenuBean implements Serializable {
 
 private static final long serialVersionUID = 1L;
 private static final String menuReaderTypeKey="menuBeanReaderType";
 
 @Getter  
 private MenuModel menuModel;
 
 @Inject 
 ApplicationProperties appProps;
 
 @Inject
 Instance<IMenuBeanReader> unqualifiedMenuBeanReader;
 
 private IMenuBeanReader myMenuBeanReader;
 
 @PostConstruct
        public void init() {
        
       String myReaderType=this.appProps.getProperty(menuReaderTypeKey);
     
       // get desired implementation of menuBeanReader by injection 
       myMenuBeanReader = unqualifiedMenuBeanReader.select(new MenuBeanReaderTypeDescriptor(myReaderType)).get();
     
 }
 
    /**
     * Reads the menu structure from a Json file using a class for that purpose.
     * @param isRelativeToResourceFolder (if relative Paths are used to access the config file)
     * @param fileName (Name of the file where configuration is stored)
     */
    public void readMenu(boolean isRelativeToResourceFolder, String fileName) {
     
     menuModel = new DefaultMenuModel();
     System.out.println("MenuBean.readMenu(" + isRelativeToResourceFolder + "," + fileName + ")" );
     
     try {
   //new MenuBeanReaderJSONRelativePath().readMenu(fileName, menuModel);
      myMenuBeanReader.readMenu(fileName, menuModel);
      
      
  } catch (IOException | MenuJsfException e) {
   
   e.printStackTrace();
  }
    }
}    
    

The property file application.properties is the same as in the previous post


1
2
3
4
5
webEnvironment=true
menuBeanReaderType=MenuBeanReaderJSONRelativePath
comment=This is a test commennt
kk=Other property
greet.first=Good Morning!

So the injected class is MenuBeanReaderJSONRelativePath, so the the attribute myMenuBeanReader will be transformed to this class instance by the sentence

myMenuBeanReader = unqualifiedMenuBeanReader.select(new MenuBeanReaderTypeDescriptor(myReaderType)).get();

That's all for now. I hope it wil be clearer

jueves, 17 de agosto de 2017

JEE & JSF 5th Part: Accessing property files EASIER

0. Introduction

To show formatted text Hilite is used

The goals of this post are:

  1. Locating the properties file
  2. Creating an ApplicationScoped bean to store these properties
  3. Accessing this bean by injection from another bean.


1. Locating the properties file.


We need to know where to locate the property files. Let's create an easy class to locate the property file. this class is Configuration.java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package org.ximodante.jsf.config;


import lombok.Getter;

/**
 * Locate of configuration files "application.properties"
 * @author Ximo Dante
 *
 */
public class Configuration {
 @Getter
 private static final String PropertyFile="config/application.properties";
 
}


This path is relative to src/main/resources folder


2. ApplicationProperty class

This class gets the path to file "application.properties" from last class, loads the properties included in this file and provides a getter method for retrieving the properties. But this class is application scoped, which means that it behaves as a singleton.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.ximodante.utils.property;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

import org.ximodante.jsf.config.Configuration;

@Named
@ApplicationScoped
/**
 * Stores properties from file Application.properies whose path can be read in Configuraion.getPropertyfile() 
 * @author Ximo Dante
 *
 */
public class ApplicationProperties implements Serializable{
 private static final long serialVersionUID = 1L;

 private Properties properties;
 
 /**
  * Getter method of the properties by a key
  * @param key
  * @return
  */
 public String getProperty(String key){
  return properties.getProperty(key);
 }
 
 /**
  * The properties are load in the initilization part
  */
 @PostConstruct
    public void init() {
        this.properties = new Properties();
        
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + Configuration.getPropertyFile();
        System.out.println("PROPERTIES.PATH=" + path);
        
        try {
            //this.properties.load(stream);
         this.properties.load(new FileInputStream(path));
        } catch (final IOException e) {
            throw new RuntimeException("Application.properties could not be loaded!");
        }
    }
}


The file application.properties has this content:



1
2
3
4
5
webEnvironment=true
menuBeanReaderType=MenuBeanReaderJSONRelativePath
comment=This is a test commennt
kk=Other property
greet.first=Good Morning!

3. Retrieving properties from a bean


Let's create a bean called TestProperties that injects the last class and retrieves a property, for instance, "menuBeanReaderType" whose value is "MenuBeanReaderJSONRelativePath"



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.ximodante.utils.property;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import lombok.Getter;

@Named
@ViewScoped
public class TestProperties implements Serializable{
 private static final long serialVersionUID = 1L;
 
 @Inject 
 ApplicationProperties appProps;
 
 @Getter
 private String myReaderType;
 
 @PostConstruct
    public void init() {
        
     myReaderType=this.appProps.getProperty("menuBeanReaderType");
     System.out.println("Accessed property is:" + myReaderType);
 }
}

And let's modify out later Facelets file tutorial01-menu.xhtml to view the attribute myReaderType as follows


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core" 
      xmlns:p="http://primefaces.org/ui">  
     
  <h:head>  
  </h:head>  
      
  <h:body>  
    
      
      <h:form>
        <p:layout fullPage="true">
 
        
          <p:layoutUnit position="west" size="200" header="Left" resizable="true" closable="true" collapsible="true" effect="drop">
          
          
          
            <p:growl id="messages" showDetail="false"/>
              
            <p:panelMenu id="menu01" model="#{menuBean.menuModel}"/>
 
        
          </p:layoutUnit>
        
          <p:layoutUnit position="center">
            Content panel PROPERTY GOT:--> #{testProperties.myReaderType}    
            <p:commandButton value="Update Menu02" id="menuupd02" actionListener="#{menuBean.readMenu(true,'config/menu02.json')}" icon="ui-icon-disk" update="menu01"/>       
            <p:commandButton value="Update Menu"   id="menuupd"   actionListener="#{menuBean.readMenu(true,'config/menu.json')}"   icon="ui-icon-disk" update="menu01"/>       
            
          </p:layoutUnit>
 
        </p:layout>
     </h:form>
      
   
  </h:body>  
</html>Serializable{
 private static final long serialVersionUID = 1L;
 
 @Inject 
 ApplicationProperties appProps;
 
 @Getter
 private String myReaderType;
 
 @PostConstruct
    public void init() {
        
     myReaderType=this.appProps.getProperty("menuBeanReaderType");
     System.out.println("Accessed property is:" + myReaderType);
 }
}


4. Running ...

Right click on the file "tutorial01-menu.xhtml" and select Run As- Run On Server

and the result is:





martes, 8 de agosto de 2017

JEE & JSF 3rd Part: Accessing property files (I DON'T LIKE THIS POST. I FIND IT TOO ARTIFICIOUS. ONLY FOR LEARNING PURPOSES)

0. Introduction

Although this is a "very academical" post, I don't like it as it is too verbose and difficult to understand. So I prefer using this approach to use properties.

To show formatted text Hilite is used



Getting a property from a property file is rather simple in Java. But it is a very resource consuming practice to create a Properties class every time a property is read (and accessing a file).

So a good choice is to use a singleton instance.

To achieve this post, the help of these post have been greatly appreciated:
  1. Baeldung, Mykong. (For accessing property files)
  2. Ivo Woltring, Piotr Nowicki (For singletons)

A Singleton is very similar to an application scoped bean, so the second approach will be used. the use of Weld is very important as a context and dependency manager container.

The steps of this tutorial are:

  1. Create an Eclipse Maven project as the one created in the last post, or use it. 
  2. Create an Interface to define an annotation of Property.
  3. Create the Producer (but Ivo and Piotr have distinguished the data type of property)
  4. Creating the property files (application.properties)
  5. Using in an example
Let's begin with the second step.

1. Creation of the Property Annotation (Interface)

Our code is:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.ximodante.utils.property;

import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;


/**
 * Represents an property key to be injected
 */
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Property {
    @Nonbinding String value() default "";
    @Nonbinding boolean required() default true;
}

Brief explanations:
@Retention (RUNTIME) for accessing during Runtime
@target indicates in which part of the code can be used
@Nonbinding: "If a member has this qualifier, it will not be used during type-safe resolution and its value will have no meaning". This is what says, Ken Finnegan


2. The Producer class

Ivor and Piotr have made a "fine" producer, analyzing the property type. I cannot improve this class So a copy-paste is made, but some modifications are made:

  1. @ApplicationScoped annotation for making it quite similar to a singleton.
  2. Some additional System.out.println sentences to see whether the property file is accessed and to evaluate how many times the property file is opened
  3. An additional class Config is accessed to know where is the property file. The file is in "config/application.properties" in the src/main/resources folder
  4. Should implement Serializable or else Weld complaints


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package org.ximodante.utils.property;

import java.io.FileInputStream;
import java.io.IOException;

import java.io.Serializable;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;


import org.ximodante.jsf.config.Config;

@ApplicationScoped
public class PropertyProducer implements Serializable{
 
 private static final long serialVersionUID = 1L;
 
 private Properties properties;
 
  
    @Property
    @Produces
    public String produceString(final InjectionPoint ip) {
        return this.properties.getProperty(getKey(ip));
    }
    
    @Property
    @Produces
    public int produceInt(final InjectionPoint ip) {
        return Integer.valueOf(this.properties.getProperty(getKey(ip)));
    }
    
    @Property
    @Produces
    public boolean produceBoolean(final InjectionPoint ip) {
        return Boolean.valueOf(this.properties.getProperty(getKey(ip)));
    }
    
    private String getKey(final InjectionPoint ip) {
        return (ip.getAnnotated()
                  .isAnnotationPresent(Property.class) && 
                !ip.getAnnotated()
                   .getAnnotation(Property.class)
                   .value().isEmpty()) ? ip.getAnnotated()
                                           .getAnnotation(Property.class)
                                           .value() 
                                       : ip.getMember()
                                           .getName();
    }
    
    @PostConstruct
    public void init() {
        this.properties = new Properties();
        
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + Config.getPropertyFile();
        System.out.println("PROPERTIES.PATH=" + path);
        
        try {
            //this.properties.load(stream);
         this.properties.load(new FileInputStream(path));
        } catch (final IOException e) {
            throw new RuntimeException("XXXXXXXX: Configuration could not be loaded!");
        }
    }

}


3. The application.properties file

Our file  in "config/application.properties" in the src/main/resources folder is



1
2
3
4
webEnvironment=true
comment=This is a test commennt
kk=Other property
greet.first=Good Morning!

To localize the path of the file the Config class is used.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package org.ximodante.jsf.config;


import lombok.Getter;

public class Config {
 @Getter
 private static final String PropertyFile="config/application.properties";
 
}


4. Using in a bean.

The source code for a simple bean is



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.ximodante.utils.property;

import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import lombok.Getter;

@Named
@ViewScoped
public class TestPropertyBean implements Serializable{
 private static final long serialVersionUID = 1L;
 
 // the name of the attribute (greet1= does NOT match 
 // the property name ("greet.fist")
 @Inject
 @Property("greet.first")
 @Getter
 private String greet1;
 
 // the name of the attribute (comment) DOES match 
 // the property name so no attribute is passed to 
 // the annotation @Property
 @Inject
 @Property
 @Getter
 private String comment;
 
}

To make this easier a xhtml file is supplied (beanprop.xhtml) in webapp folder



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
       <h:form>  
           <p:panel header="Keyboard Demo">    
               <p:keyboard value="#{testPropertyBean.comment}"/>  
               <p:keyboard value="#{testPropertyBean.greet1}"/>  
             </p:panel>
             <p:commandButton value="Submit"/>
       </h:form>
    </h:body>  
</html>


Let's run the project as a server application and point to http://localhost:8080/JSFv02/beanprop.jsf in the browser where:

- JSFv02 is the name of our project
beanprop.jsf references to the beanprop.xhtml file in the webapp folder

Here is the result









martes, 25 de julio de 2017

JEE & JSF 2on Part: Weld dependencies

Introduction


To show formatted text Hilite is used



Our goal is to configure an Eclipse Maven JSF2 2.2 and CDI with Tomcat.

Weld reports a great problem for servlet containers :



  1. NO SESSION SCOPED BEANS can be used,
  2. NO @EJB INJECTION can be used.
  3. NO @PersistentContext INJECTION can be used.
  4. NO TRANSACTIONAL EVENTS can be used.
So the previous example where a @SessionScoped bean was defined SHOULD NOT WORK (OR MAYBE IT CAN WORK)



Defining Maven dependencies



As mentioned in BalusC Blog these dependencies will be referenced :


  1.  weld-servlet-shaded.jar (requiered)
  2.  validation-api.jar (optional for bean validation)
  3.  hibernate-validator.jar (optional for bean validation)

Our pom.xml file may be this one


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.ximodante.jsf</groupId>
  <artifactId>JSFv02</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>JSFv02</name>
  <description>JSF 2.2 &amp; CDI</description>
 
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>
  
  <dependencies>
     
    <!-- Servlet 3.1 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    
    <!--  JSF 2.2 API -->
    <dependency>
     <groupId>com.sun.faces</groupId>
     <artifactId>jsf-api</artifactId>
     <version>2.2.14</version>
    </dependency>

    <!--  JSF 2.2 Implementation -->
    <dependency>
     <groupId>com.sun.faces</groupId>
     <artifactId>jsf-impl</artifactId>
     <version>2.2.14</version>
    </dependency>

    <!--  Primefaces -->
    <dependency>
     <groupId>org.primefaces</groupId>
     <artifactId>primefaces</artifactId>
     <version>6.1</version>
    </dependency>

    <!--  Primefaces Themes -->
    <dependency>
     <groupId>org.primefaces.extensions</groupId>
     <artifactId>all-themes</artifactId>
     <version>1.0.8</version>
     <type>pom</type>
    </dependency>
    
    <!-- Weld CDI for Tomcat (does not fulfill all capabilities !!!) -->
    <dependency>
      <groupId>org.jboss.weld.servlet</groupId>
      <artifactId>weld-servlet-shaded</artifactId>
      <version>3.0.0.Final</version>
    </dependency>
    
    <!-- Validation API Optional -->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>2.0.0.CR3</version>
    </dependency>
        
    <!-- Hibernate Bean Validator Optional -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.4.1.Final</version>
    </dependency>
    
  </dependencies> 
  
</project>



Creating additional files



These files are our candidates for being created in our webapp folder:

  1. META-INF/context.xml (not necessary for Mojarra version > 2.2.11 ( using now 2.2.14)
  2. WEB-INF/beans.xml (empty file)
NOTE: I have encountered an error on Maven reporting that failed to read artifact descriptor for hibernate-validator dependency. There are different solutions to this issue is in stackoverflow and this other one stackoverflow.


Updating existing files


As mentioned above we SHOULD NOT use CDI @SessionScoped Beans with Tomcat, (we could use @ViewScoped instead .... but for now I will only change the @SessionScoped reference of this dependence to Weld javax.enterprise.context.SessionScoped)

The new annotation replacement for @ManagedBean is @Named according to Weld

But our class must implement Serializable interface in order to avoid this error

Managed bean KeyboardBean which declares a passivating scope SessionScoped must be passivation 

 capable [JSR-346 §6.6.5]

Our class KeyboardBean will be now:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.ximodante.jsf;

//import javax.faces.bean.ManagedBean;
//import javax.faces.bean.SessionScoped;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;



//@ManagedBean
@Named
@SessionScoped

public class KeyboardBean implements Serializable {
   
 private static final long serialVersionUID = 1L;
 
 private String value="12345";
 
 public String getValue() {
  System.out.println("KeyboardBean::reading value: " + value);
        
        return value;
    }
    public void setValue(String value) {
     System.out.println("KeyboardBean::setting value: " + value);
        
        this.value = value;
   }    
}


Let's execute as last post Run As - Run on Server, select tomcat and our URL is:

http://localhost:8080/JSFv01/index.jsf 

And everything should go as last post




JEE & JSF16th Part: Creating an abstraction view layer to JSF components and Forms (5/5). Frequent problems

1. ERROR #1: Using a bean that does not exists In the previos entry we used this facelet file: 1 2 3 4 5 6 7 8 9 10 11 1...