lunes, 18 de septiembre de 2017

JEE & JSF12th Part: Creating an abstraction view layer to JSF components and Forms (1/5). Description classes

0. Introduction

So far, we have learned to create JSF components programmatically with the desired properties and actions.

Imagine you want to migrate your application to another framework.

A way to achieve this is using classes that :

  1. Hold or retrieve the necessary information to describe the desired forms or components.
  2. Create the components programmatically (Builders)
Let's create a new java package called org.ximodante.jsf.component

In this entry, we will focus on the structure and classes that define components, attributes, actions and so on. 

1. AttributeType structure

This structure defines the type of an element of a component (I have decided it to be one of the following:

  1. property
  2. action
  3. array (of child components)
  4. other

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

/**
 * 
 * @author Ximo Dante
 * A compompent attribute can be :
 *   1. property that can be accessed by a getter/setter
 *   2. action from a button, etc
 *   3. array like children, ...
 *   4. other
 *
 */
public enum AttributeType {
 PROPERTY,
 ACTION,
 ARRAY,
 OTHER
}


2. ComponentAttribute class

It is intended to have a catalogue of all attributes so that we can detect if a not catalogued attribute is proposed to be employed.

The attribute has a name and belongs to a defined class. Here is the source:


 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.component;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
 * 
 * @author ximo Dante
 * 16/9/2017
 * name: name of attribute
 * setter : if the setter is buid by set + Name
 * pclass : class of the parameter or argument of setter
 * comment: comments
 */

@NoArgsConstructor @AllArgsConstructor
public class ComponentAttribute {
 @Getter @Setter private String name;
 @Getter @Setter private AttributeType type=AttributeType.PROPERTY;
 @Getter @Setter private String pclass;
 @Getter @Setter private String comment="This is a comment";
}

3. ComponentType class

It is intended to have a catalogue of all component types so that we can detect if a not catalogued component is intended to be used.

As we know there are some jsf components from different libraries that share the same name. So let's append a letter prefix and an underscore to the name to distinguish them.

For instance, the name "h_HtmlPanelGroup" is used to represent a panel of the class "javax.faces.component.html.HtmlPanelGroup"

The component type class 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.jsf.component;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
 * 
 * @author ximo Dante
 * 15/9/2017
 * name: prefix + "_" + name of component
 * container : if can have children
 * qclass : qualified class
 * comment: comments
 */
@NoArgsConstructor @AllArgsConstructor
public class ComponentType {
 @Getter @Setter private String name;
 @Getter @Setter private boolean container;
 @Getter @Setter private String qclass;
 @Getter @Setter private String comment;
 
} 

4. Exceptions

Let's create an Exception class for this package:


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

/**
 * Exception for component building
 * @author Ximo Dante
 *
 */
public class ComponentJsfException extends Exception{
 private static final long serialVersionUID = 1L;

 public ComponentJsfException(String message) { 
  super(message); 
 }
 

}

martes, 12 de septiembre de 2017

JEE & JSF11th Part: Setting EL expresions to component properties programmatically.

0. Introduction

Maybe, JSF has not been designed to create elements programmatically, or perhaps, I have not understood JSF philosophy at all. But applications containing many beans can be rather cumbersome if you do no automatise some tasks. Model-driven development system can be a good strategy.

Frameworks like OpenXava are interesting examples of this approach. The leader of this project is Javier Paniza a person who I admire.

Java owns great resources as Reflection that enables us to manage classes that can be unknown at development time.

1. Updating our pom.xml with el-api dependency

In our system with Eclipse Neon 3 and Tomcat 9, we need to add the el-api dependency to our pom.xml.


  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
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<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>JSFv01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>JSFv01</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>
    
    <!-- To solve Tomcat problem : java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </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>
    
    <!--  Lombok for setters and getters -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.18</version>
    </dependency>
    
    <!-- JSON -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>

    <!-- Apache Commons Utils -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.6</version>
    </dependency>
    
    <!-- Apache Commons Text -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-text</artifactId>
      <version>1.1</version>
    </dependency>
    
    
    <!--  JPA Hibernate -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.10.Final</version>
    </dependency>
    
    <!--  PostgreSQL -->
    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.4.1212</version>
    </dependency>
    
    
    <!-- Primeface Extensions -->
    <!-- https://mvnrepository.com/artifact/org.primefaces.extensions/primefaces-extensions -->
    <dependency>
      <groupId>org.primefaces.extensions</groupId>
      <artifactId>primefaces-extensions</artifactId>
      <version>6.1.1</version>
    </dependency>
    
    <!--  for evaluating EL expressions -->
    <!-- https://mvnrepository.com/artifact/javax.el/javax.el-api 16/9/2017-->
    <dependency>
      <groupId>javax.el</groupId>
      <artifactId>javax.el-api</artifactId>
      <version>3.0.1-b04</version>
    </dependency>

  </dependencies> 
  
</project>


2. Creating JSF Value and Action Expressions.

This simple facelets code:


1
<h:outputText value="#{personBean.surname}" />

cannot be accomplished in Java code as:


1
myOutputText.setValue("#{personBean.surname}")


In the first case (Facelets), the value of the attribute "surname" is displayed. In the second sample,
"#{personBean.surname}" is interpreted literally as a string.

David Pisano, explains briefly how to achieve this goal. To accomplish this, these 2 steps should be performed:

  1. Convert a string to a ValueExpression object
  2. Use component method setValueExpression in this way:


1
myOutputText.setValueExpression(String property, ValueExpression expression)  


where property, is the name of the property to be assigned, in this case, "name" and expression is the object obtained from converting "#{personBean.surname}" to ValueExpression,

But the same thing happens when setting actions to buttons like components. We need an ActionExpression object. It is explained by John Yeary.

In this case, the 2 steps are
  1. Convert a string to an MethodExpression object
  2. Use component method setActionExpression in this way:


1
myButton.setActionExpression(MethodExpression expression)  


A Java utility class with static methods is included to get ActionExpressions and ValueExpressions:


 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
package org.ximodante.utils.jsf;

import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;

public class JSFUtils {
 /**
  * Creates a {@link ValueExpression} that wraps an object instance. This
  * method can be used to pass any object as a {@link ValueExpression}. The
  * wrapper {@link ValueExpression} is read only, and returns the wrapped
  * object via its {@code getValue()} method, optionally coerced.
  *
  * @param expression The expression to be parsed.
  * @param expectedType The type the result of the expression will be coerced
  * to after evaluation.
  * @return The parsed expression.
  * @see http://javaevangelist.blogspot.com.es/2012/10/jsf-2x-tip-of-day-programmatically.html
  */
 public static ValueExpression createValueExpression(String expression, Class<?> expectedType) {
     FacesContext context = FacesContext.getCurrentInstance();
     return context.getApplication().getExpressionFactory()
             .createValueExpression(context.getELContext(), expression, expectedType);
 }
 
 /**
  * 
  * @param expression
  * @return
  * @see http://jannotation.blogspot.com.es/2012/10/jsf-setting-el-expression.html
  */
 public static ValueExpression createValueExpression(String expression) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Application app = facesContext.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = facesContext.getELContext();
        ValueExpression valueExp =
              elFactory.createValueExpression(elContext,
                                              expression,
                                              Object.class);
        return valueExp;
    }
 
 /**
  * This is a convenience method that parses an expression into a
  * {@link MethodExpression} for later evaluation. Use this method for
  * expressions that refer to methods. If the expression is a {@code String}
  * literal, a {@link MethodExpression} is created, which when invoked,
  * returns the {@code String} literal, coerced to expectedReturnType. An
  * {@link ELException} is thrown if expectedReturnType is {@code void} or if
  * the coercion of the {@code String} literal to the expectedReturnType
  * yields an error. This method should perform syntactic validation of the
  * expression. If in doing so it detects errors, it should raise an
  * {@link ELException}.
  *
  * @param methodExpression The expression to parse.
  * @param expectedReturnType The expected return type for the method to be
  * found. After evaluating the expression, the {@link MethodExpression} must
  * check that the return type of the actual method matches this type.
  * Passing in a value of {@code null} indicates the caller does not care
  * what the return type is, and the check is disabled.
  * @param expectedParamTypes The expected parameter types for the method to
  * be found. Must be an array with no elements if there are no parameters
  * expected. It is illegal to pass {@code null}, unless the method is
  * specified with arguments in the EL expression, in which case these
  * arguments are used for method selection, and this parameter is ignored.
  * @return The parsed expression.
  * @see http://javaevangelist.blogspot.com.es/2012/10/jsf-2x-tip-of-day-programmatically_20.html
  */
 public static MethodExpression createMethodExpression(String methodExpression, Class<?> expectedReturnType, Class<?>[] expectedParamTypes) {
     FacesContext context = FacesContext.getCurrentInstance();
     return context.getApplication().getExpressionFactory()
             .createMethodExpression(context.getELContext(), methodExpression, expectedReturnType, expectedParamTypes);
 }
 









jueves, 31 de agosto de 2017

JEE & JSF 10th Part: NO GOOD, SKIP READING!!!! Primefaces FluidGrid (component extension)

0. Introduction

I have been analysing both DynaForm and FuidGrid as they can manage better the alignment of the displayed controls. They belong to Primefaces extensions. But for the moment, I have decided to use FluidGrid as it is responsive.

the aim is creating responsive forms programmatically.

1. Defining dependencies to pom.xml

The Primeface extensions dependency in maven is:


1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.primefaces.extensions/primefaces-extensions -->
<dependency>
    <groupId>org.primefaces.extensions</groupId>
    <artifactId>primefaces-extensions</artifactId>
    <version>6.1.1</version>
</dependency>

So our final pom.xml file 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
 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
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<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>JSFv01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>JSFv01</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>
    
    <!-- To solve Tomcat problem : java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </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>
    
    <!--  Lombok for setters and getters -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.18</version>
    </dependency>
    
    <!-- JSON -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>

    <!-- Apache Commons Utils -->
    <dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-lang3</artifactId>
     <version>3.6</version>
    </dependency>
    
    <!--  JPA Hibernate -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.10.Final</version>
    </dependency>
    
    <!--  PostgreSQL -->
    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.4.1212</version>
    </dependency>
    
    
    <!-- Primeface Extensions -->
    <!-- https://mvnrepository.com/artifact/org.primefaces.extensions/primefaces-extensions -->
    <dependency>
      <groupId>org.primefaces.extensions</groupId>
      <artifactId>primefaces-extensions</artifactId>
      <version>6.1.1</version>
    </dependency>

  </dependencies> 
  
</project>


2. Defining the facelets file




martes, 29 de agosto de 2017

JEE & JSF 9th Part: Creating JSF controls programmatically

0. Introduction

Medium and large application (management applications that use many entities) can follow a Domain Driven Design.  

I like this approach as I think that integrates with object-oriented paradigm. Each entity is defined by its properties (attributes) and its interaction with the rest (methods).

If we can survey into an entity to see its definition (attributes and methods) we can create some visual prototypes with controls to edit its properties with buttons (or equivalent components) to execute its methods. 

The main idea is considering an object like a set of attributes and methods. Exploring this set may enable us to build dynamically this prototype. The most important thing is that all windows look like very similar and so, training process gets simple. Once you see how to use a window, the rest of the windows are siblings.

So our prototype should be able to add components to the window dynamically using information from the attributes (type, validation restrictions etc) and the methods (parameters, result, etc.)

The main tools are supplied by Java (Reflection,  Bean Validation, etc) but we also need that JSF enables us to add components programmatically at run-time. 

1. Creating a JSF component using Java

There are mainly 2 ways of  creating a JSF component

1. Using new Component(). For instance to create a HtmlInputText:

   HtmlInputText txtControl2= new HtmlInputText();

2. Using FacesContext.getCurrentInstance().getApplication().createComponent().


HtmlInputText txtControl2= =(HtmlInputText) FacesContext.getCurrentInstance().getApplication().createComponent(HtmlInputText.COMPONENT_TYPE);

The last one is mainly recommended.

2. Binding a JSF container component in a facelets file

Let's create a bean that has a form attribute. We need a @Postconstruct init method (line 27) to create the form

DynamicBeanExample.java


 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.dynamic;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.component.html.HtmlForm;
/********************************************************
 * CAREFUL USE: import javax.faces.view.ViewScoped 
 *  DO NOT USE: import javax.bean.view.ViewScoped
 ********************************************************/
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import lombok.Getter;
import lombok.Setter;

@Named
@ViewScoped
public class DynamicBeanExample implements Serializable {

 private static final long serialVersionUID = 1L;
 
 @Getter @Setter
 private HtmlForm myForm;
 
 
 @PostConstruct
 public void init() {
  myForm = new HtmlForm(); 
 }
}

Note Lombok getter and setter annotations!

Now our facelet file is

dynamic01.xhtml:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    
    <h:head>  
    </h:head>  
      
    <h:body>  
       <h:form binding="#{dynamicBeanExample.myForm}">
           Hello.....
           
       </h:form>
    </h:body>      
 
</html>

Note in line 11 how the form is bound to the form created in the bean.

3. Adding JSF child components to a container.

The getChildren() method return a list of the nested components of a container. Adding a created component is as easy as using add method of a List.


1
2
3
4
HtmlOutputLabel lbl=new HtmlOutputLabel();
lbl.setValue("This is a Label");

myForm.getChildren().add(lbl);

This code can be merged to the init method of the bean (DynamicBeanExample.java) to add a label to the form.

Now we have got a super simple and useless form. But it is a good example for educational purposes only!



lunes, 28 de agosto de 2017

JEE & JSF 8th Part: Using JPA 2.1 (2/2). JPA with JSF integration

0. Introduction


Understanding how JSF works is a bit difficult for me. In StackOverflow, the possibility of making a singleton object for an entity manager is suggested.

The idea is making a complex application that uses several schemes of the database, but even this approach can be achieved using only one entity manage, as the scheme is chosen when defining the POJO (the class to persist that contains JPA annotations).

It can be interesting to have several persistence units in out persistence.xml file so that we can select our database scenario (we can use for development H2, Derby etc and for deployment Postgresql or MariaDB etc) making use of a property file for choosing our persistent unit.

But as reported in StackOverflow it can be interesting using different implementations of JPA (Hibernate, EclipseLink, TopLink, OpenJPA, DataNucleus, ObjectDB), but also some, not JPA approaches that can be taken into account (JDBC, ORM Hibernate, MyBatis, JDO..)

So, our soul mate CDI can help us in this way:
  1. We can design an interface that defines our desired CRUD (Create, read, update, write ...) functionality 
  2. In a property/configuration file, we can choose the desired implementation of the interface.
  3. By means of CDI, we can use the chosen implementation as pointed out in a previous post.

In the sake of simplicity, we can design the interface with only some capabilities of a JPA entity manager.

1. CRUD Interface (main interface)


This interface defines only some basic CRUD functions for teaching purpose only. This file is IDAO.java



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

public interface IDAO {
 // 1. begin transaction
 public void beginTrans();
 
 // 2. commit transaction
 public void commitTrans();                     
 
 // 3. create an entity in the DB
 public void persist(java.lang.Object entity);  
 
 // 4. remove an entity from the DB
 public void remove(java.lang.Object entity);   
 
 // 5. Retrieve an entity from the DB
 public <T> T find(java.lang.Class<T> entityClass, java.lang.Object primaryKey);
 
 // 6. Update an entity in the DB
 public void refresh(java.lang.Object entity);   
}


2. The annotation interface (to assign a "key" to pick the desired implementation)

This annotation is used to label the classes that implement the main interface. This file is IDAOType.java



 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.jpa;

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 IDAO interface
 * @author Ximo Dante
 *
 */
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface IDAOType {
 
    String type() default "JPA-Hibernate";
}



3. The class to be injected that implements IDAO (main interface)


In this case, we are using only one implementation of the IDAO interface. Why on earth wasting so much effort using injection if there is only one candidate for injection? This is maybe what you are thinking! But if we consider another implementation in a near future, all the scaffolding has been built.

Don't forget to make this class Serializable !!!!

This is the class: DAOJPAHibernate.java



 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
package org.ximodante.utils.jpa;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.ximodante.utils.property.ApplicationProperties;


@Named
@ApplicationScoped                // Singleton
@Default
@IDAOType(type="JPA-Hibernate") // for selecting the object at run time with CDI
public class DAOJPAHibernate implements IDAO, Serializable{
 
 private static final long serialVersionUID = 1L;
 
 private static final String JPAPersistenceUnitKey="JPAPersistenceUnit";
 private EntityManagerFactory emf = null;
 private EntityManager em = null;
 
 @Inject
 ApplicationProperties appProps;
 
 @Override
 public void beginTrans() {
  em.getTransaction().begin();
 }

 @Override
 public void commitTrans() {
  em.getTransaction().commit();
 }

 @Override
 public void persist(Object entity) {
  em.persist(entity);  
 }

 @Override
 public void remove(Object entity) {
  em.refresh(entity);
 }

 @Override
 public <T> T find(Class<T> entityClass, Object primaryKey) {
  return em.find(entityClass, primaryKey);
 }

 @Override
 public void refresh(Object entity) {
  em.refresh(entity);
 }
 
 /**
  * Creates the entity manager object needed to operate.
  */
 @PostConstruct
    public void init() {
  String myPersistenceUnit=appProps.getProperty(JPAPersistenceUnitKey);  // my_jap_test
  System.out.println("myPersistenceUnit="+myPersistenceUnit);
  this.emf = Persistence.createEntityManagerFactory(myPersistenceUnit);
  this.em = emf.createEntityManager();
  
 }

}

It is important to note that the Persistence unit is obtained from the file application.properties as shown in a previous post for getting properties. Now to the application.properties file 2 new entries have been added:



1
2
DAOProvider=JPA-Hibernate
JPAPersistenceUnit=my_jpa_test

The first one DAOJPAProvider will select our injection class
The second one JPAPersistenceUnit will select our persistence unit (defined in persistence.xml file) in case that the IDAO implementation is a JPA compliant. In this case, we are using "my_jpa_test"


4. 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 implement the main interface.

This class is DAOTypeDescription 


 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
import javax.enterprise.util.AnnotationLiteral;
/**
 * Class that is a tool to manage the parameter "type" from the Annotation IDAOType 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 DAOTypeDescriptor extends AnnotationLiteral<IDAOType> implements IDAOType{
 private static final long serialVersionUID = 1L;
 
 private String type;
    
 public DAOTypeDescriptor(String type) {
        this.type = type;
    }
 

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


5. Injecting into a bean


In this case, the bean is DAOBean.java:



 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
package org.ximodante.utils.jpa;

import java.io.Serializable;

import lombok.Getter;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;

import org.ximodante.utils.property.ApplicationProperties;


/**
 * 
 * @author Ximo Dante
 * @date 29/08/2017
 *
 */
@Named
@SessionScoped
public class DAOBean implements Serializable {
 
 private static final long serialVersionUID = 1L;
 private static final String DAOProviderKey="DAOProvider";
 
 @Inject 
 ApplicationProperties appProps;
 
 @Inject
 Instance<IDAO> unqualifiedDAO;
 
 @Getter
 private IDAO myDAO;
 
 @PostConstruct
        public void init() {
        
       String myDAOType=this.appProps.getProperty(DAOProviderKey);
       System.out.println("myDAOType=" + myDAOType);
     
       // get desired implementation of IDAO by injection 
       myDAO = unqualifiedDAO.select(new DAOTypeDescriptor(myDAOType)).get();
     
    }
 public String myName (Long id){ 
  
  myDAO.beginTrans();
  Person ps = myDAO.find(Person.class, id);
  myDAO.commitTrans();
  
  return ps.getName();
 }
}    

Note:
 Line 38: The initializing method with @PostConstruct annotation for selecting the class to inject.
 Line 41: Gets from the property file who is the DAO provider
 Line 45: Get the proper IDAO implementation class by its labelled annotation     @IDAOType (type = "JPA-Hibernate") 
  that belongs to our implementing class

 Line 48: A method for teaching purposes to be used in a xhtml file. This method retrieves the name of the person whose id is 14 (In this case is "Juanito")

6. The facelet file for testing

Let's use a modification of the file beanprop.xhtml



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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:keyboard value="#{dAOBean.myName(14)}"/>
             </p:panel>
             <p:commandButton value="Submit"/>
       </h:form>
    </h:body>  
</html>

Note:
 Line 13 that executes the method myName of the DAOBean passing the id parameter=14. 

And if we right-click on the file beanprop.xml and Run on Server, we can get this view


We can see "Juanito" in the last input box.

Great!





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...