The Bean Class for JavaFX Programming

      1 Comment on The Bean Class for JavaFX Programming

In my earlier article, The Bean Class for Java Programming, I presented how I want you, my students, to code a data or model class in your assignments. That style of bean class is widely used in frameworks such as Hibernate, Java Server Faces, CDI and others. There is one variant of that class that you need to know about and that is the JavaFX bean class.

JavaFX is the modern GUI framework that is the successor to Swing as it was the successor to AWT. One important characteristic of JavaFX is that the observable pattern is baked into its beans, pun intended. When a JavaFX bean is bound or connected to a JavaFX control. such as a text field, changes to the control can automatically update the bean and changes to the bean updates the control. This is an important feature in the Model View Controller pattern that JavaFX promotes.

A JavaFX bean, when properly constructed, can be a drop-in replacement for a Java bean in most instances. It is expected to adhere to all the mandatory, optional and even bonus features I described in the earlier article. Let’s begin by reviewing the fields from that article.

[pastacode lang=”java” manual=”%20%20%20%20private%20String%20isbn%3B%0A%20%20%20%20private%20String%20title%3B%0A%20%20%20%20private%20String%20author%3B%0A%20%20%20%20private%20String%20publisher%3B%0A%20%20%20%20private%20int%20pages%3B” message=”” highlight=”” provider=”manual”/]

I have added an additional field to make this bean a little more interesting. The field will represent the date that the book was published.

[pastacode lang=”java” manual=”%20%20%20%20private%20LocalDate%20datePublished%3B” message=”” highlight=”” provider=”manual”/]

To make this bean observable we must change how we declare these fields. JavaFX introduced a family of wrapper classes called property classes. These property classes exist for the primitive types, the String, List, Map, Object, Set and a catch all for any other class type. These classes come in read / write as well as read only versions. They also come in abstract and concrete classes. The abstract class is the property type (LHS) and the concrete class is the instantiation (RHS). Here is a table of the read / write property classes.

[pastacode lang=”java” manual=”Abstract%20%2F%20LHS%20Type%09%20Concrete%20%2F%20RHS%20Type%0A———————————————-%0ABooleanProperty%20%20%20%20%20%20SimpleBooleanProperty%0ADoubleProperty%20%20%20%20%20%20%20SimpleDoubleProperty%0AFloatProperty%20%20%20%20%20%20%20%20SimpleFloatProperty%0AIntegerProperty%20%20%20%20%20%20SimpleIntegerProperty%0AListProperty%3CE%3E%20%20%20%20%20%20SimpleListProperty%3CE%3E%0ALongProperty%20%20%20%20%20%20%20%20%20SimpleLongProperty%0AMapProperty%3CK%2CV%3E%20%20%20%20%20SimpleMapProperty%3CK%2CV%3E%0AObjectProperty%3CT%3E%20%20%20%20SimpleObjectProperty%3CT%3E%0ASetProperty%3CE%3E%20%20%20%20%20%20%20SimpleSetProperty%3CE%3E%0AStringProperty%20%20%20%20%20%20%20SimpleStringProperty%0A” message=”” highlight=”” provider=”manual”/]

The abstract property classes define the required methods of a property in a general way. The concrete class may override the general methods but do not add any additional methods. JavaFX has other concrete property classes that can appear on the right-hand side. The concrete classes extend the abstract class. This is an example of pure inheritance.

This means that we need to rewrite the fields as follows.

[pastacode lang=”java” manual=”%20%20%20%20private%20final%20StringProperty%20isbn%3B%0A%20%20%20%20private%20final%20StringProperty%20title%3B%0A%20%20%20%20private%20final%20StringProperty%20author%3B%0A%20%20%20%20private%20final%20StringProperty%20publisher%3B%0A%20%20%20%20private%20final%20IntegerProperty%20pages%3B%0A%20%20%20%20private%20final%20ObjectProperty%3CLocalDate%3E%20datePublished%3B%0A” message=”” highlight=”” provider=”manual”/]

The next change that we make from the original bean is that we now must have a constructor. These property fields are null references to abstract classes so you must instantiate them. If you do not plan to have a non-default constructor then all you need is something like this:

[pastacode lang=”java” manual=”%20%20%20%20public%20BookFX()%20%7B%0A%20%20%20%20%20%20%20%20this.isbn%20%3D%20new%20SimpleStringProperty(%22%22)%3B%0A%20%20%20%20%20%20%20%20this.title%20%3D%20new%20SimpleStringProperty(%22%22)%3B%0A%20%20%20%20%20%20%20%20this.author%20%3D%20new%20SimpleStringProperty(%22%22)%3B%0A%20%20%20%20%20%20%20%20this.publisher%20%3D%20new%20SimpleStringProperty(%22%22)%3B%0A%20%20%20%20%20%20%20%20this.pages%20%3D%20new%20SimpleIntegerProperty(0)%3B%0A%20%20%20%20%20%20%20%20this.datePublished%20%3D%20new%20SimpleObjectProperty%3C%3E(LocalDate.now())%3B%0A%20%20%20%20%7D%0A” message=”” highlight=”” provider=”manual”/]

Each of the references to an abstract class is instantiated with a concrete class. The concrete classes all accept an appropriate value of the underlying type in their constructor.

If we need to have both a default and non-default constructor they can be written like this:

[pastacode lang=”java” manual=”%20%20%20%20public%20BookFX()%20%7B%0A%20%20%20%20%20%20%20%20this(%22%22%2C%20%22%22%2C%20%22%22%2C%20%22%22%2C%200%2C%20LocalDate.now())%3B%0A%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20public%20BookFX(final%20String%20isbn%2C%20final%20String%20title%2C%20final%20String%20author%2C%20final%20String%20publisher%2C%20final%20int%20pages%2C%20final%20LocalDate%20datePublished)%20%7B%0A%20%20%20%20%20%20%20%20this.isbn%20%3D%20new%20SimpleStringProperty(isbn)%3B%0A%20%20%20%20%20%20%20%20this.title%20%3D%20new%20SimpleStringProperty(title)%3B%0A%20%20%20%20%20%20%20%20this.author%20%3D%20new%20SimpleStringProperty(author)%3B%0A%20%20%20%20%20%20%20%20this.publisher%20%3D%20new%20SimpleStringProperty(publisher)%3B%0A%20%20%20%20%20%20%20%20this.pages%20%3D%20new%20SimpleIntegerProperty(pages)%3B%0A%20%20%20%20%20%20%20%20this.datePublished%20%3D%20new%20SimpleObjectProperty%3C%3E(datePublished)%3B%0A%20%20%20%20%7D%0A” message=”” highlight=”” provider=”manual”/]

The default constructor uses Java’s ability to have a constructor call another constructor by overloading. The non-default constructor can now be used to create an instance of the object and at the same time this class has the required default constructor.

The setters and getters must also be modified. These methods are expected to get or set the value inside the property object and not the property itself. This is easy to do as property classes have a get and set method to handle this. Here are the setters and getters.

[pastacode lang=”java” manual=”%20%20%20%20public%20final%20String%20getIsbn()%20%7B%0A%20%20%20%20%20%20%20%20return%20isbn.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setIsbn(final%20String%20isbn)%20%7B%0A%20%20%20%20%20%20%20%20this.isbn.set(isbn)%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20String%20getTitle()%20%7B%0A%20%20%20%20%20%20%20%20return%20title.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setTitle(final%20String%20title)%20%7B%0A%20%20%20%20%20%20%20%20this.title.set(title)%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20String%20getAuthor()%20%7B%0A%20%20%20%20%20%20%20%20return%20author.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setAuthor(final%20String%20author)%20%7B%0A%20%20%20%20%20%20%20%20this.author.set(author)%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20String%20getPublisher()%20%7B%0A%20%20%20%20%20%20%20%20return%20publisher.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setPublisher(final%20String%20publisher)%20%7B%0A%20%20%20%20%20%20%20%20this.publisher.set(publisher)%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20int%20getPages()%20%7B%0A%20%20%20%20%20%20%20%20return%20pages.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setPages(final%20int%20pages)%20%7B%0A%20%20%20%20%20%20%20%20this.pages.set(pages)%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20LocalDate%20getDatePublished()%20%7B%0A%20%20%20%20%20%20%20%20return%20datePublished.get()%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20setDatePublished(final%20LocalDate%20datePublished)%20%7B%0A%20%20%20%20%20%20%20%20this.datePublished.set(datePublished)%3B%0A%20%20%20%20%7D” message=”” highlight=”” provider=”manual”/]

With this syntax we now have a drop in replacement for standard Java beans as described in my first article. This is not complete yet. We are using property classes to achieve an observable pattern. To accomplish this JavaFX controls must be bound or connected to the individual fields. The controls need a reference to the property object. Only the equivalent of a getter is required. There is no naming convention because we write out the method name when we do the binding. The most common naming approach is to add the word Property to the variable name. Here are the getters for the properties.

[pastacode lang=”java” manual=”%20%20%20%20public%20final%20StringProperty%20isbnProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20isbn%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20StringProperty%20titleProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20title%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20StringProperty%20authorProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20author%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20StringProperty%20publisherProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20publisher%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20IntegerProperty%20pagesProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20pages%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20final%20ObjectProperty%3CLocalDate%3E%20datePublishedProprty()%20%7B%0A%20%20%20%20%20%20%20%20return%20datePublished%3B%0A%20%20%20%20%7D” message=”” highlight=”” provider=”manual”/]

There is not a setter for a property because once created and bound to a control it must not be replaced. Only its contained value can be altered.

The hashCode, equals, toString and compareTo methods need to be modified to use the get and set methods of the properties.

[pastacode lang=”java” manual=”%20%20%20%40Override%0A%20%20%20%20public%20String%20toString()%20%7B%0A%20%20%20%20%20%20%20%20return%20%22Book%7B%22%20%2B%20%22isbn%3D%22%20%2B%20isbn.get()%20%2B%20%22%2C%20title%3D%22%20%2B%20title.get()%20%2B%20%22%2C%20author%3D%22%20%2B%20author.get()%20%2B%20%22%2C%20publisher%3D%22%20%2B%20publisher.get()%20%2B%20%22%2C%20pages%3D%22%20%2B%20pages.get()%20%2B%20%22%2C%20datePublished%3D%22%20%2B%20datePublished.get()%20%2B%20’%7D’%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20int%20hashCode()%20%7B%0A%20%20%20%20%20%20%20%20int%20hash%20%3D%207%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.isbn.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.title.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.author.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.publisher.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20this.pages.get()%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.datePublished.get())%3B%0A%0A%20%20%20%20%20%20%20%20return%20hash%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20boolean%20equals(Object%20obj)%20%7B%0A%20%20%20%20%20%20%20%20if%20(this%20%3D%3D%20obj)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(obj%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(getClass()%20!%3D%20obj.getClass())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20final%20BookFX%20other%20%3D%20(BookFX)%20obj%3B%0A%20%20%20%20%20%20%20%20if%20(this.pages.get()%20!%3D%20other.pages.get())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.isbn.get()%2C%20other.isbn.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.title.get()%2C%20other.title.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.author.get()%2C%20other.author.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.publisher.get()%2C%20other.publisher.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.datePublished.get()%2C%20other.datePublished.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20int%20compareTo(BookFX%20book)%20%7B%0A%20%20%20%20%20%20%20%20return%20this.title.get().compareTo(book.title.get())%3B%0A%20%20%20%20%7D” message=”” highlight=”” provider=”manual”/]

The only change required to our Comparator class is to declare the beans as JavaFX beans rather than Java beans.

[pastacode lang=”java” manual=”public%20class%20BookPageComparatorFX%20implements%20Comparator%3CBookFX%3E%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20int%20compare(BookFX%20book1%2C%20BookFX%20book2)%20%7B%0A%20%20%20%20%20%20%20%20return%20book1.getPages()%20-%20book2.getPages()%3B%0A%20%20%20%20%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

Put all together this is what our JavaFX bean looks like.

[pastacode lang=”java” manual=”import%20java.io.Serializable%3B%0Aimport%20java.time.LocalDate%3B%0Aimport%20java.util.Objects%3B%0Aimport%20javafx.beans.property.IntegerProperty%3B%0Aimport%20javafx.beans.property.ObjectProperty%3B%0Aimport%20javafx.beans.property.SimpleIntegerProperty%3B%0Aimport%20javafx.beans.property.SimpleObjectProperty%3B%0Aimport%20javafx.beans.property.SimpleStringProperty%3B%0Aimport%20javafx.beans.property.StringProperty%3B%0A%0Apublic%20class%20BookFX%20implements%20Serializable%2C%20Comparable%3CBookFX%3E%20%7B%0A%0A%20%20%20%20private%20final%20StringProperty%20isbn%3B%0A%20%20%20%20private%20final%20StringProperty%20title%3B%0A%20%20%20%20private%20final%20StringProperty%20author%3B%0A%20%20%20%20private%20final%20StringProperty%20publisher%3B%0A%20%20%20%20private%20final%20IntegerProperty%20pages%3B%0A%20%20%20%20private%20final%20ObjectProperty%3CLocalDate%3E%20datePublished%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Default%20constructor%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20BookFX()%20%7B%0A%20%20%20%20%20%20%20%20this(%22%22%2C%20%22%22%2C%20%22%22%2C%20%22%22%2C%200%2C%20LocalDate.now())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Non-default%20constructor%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20isbn%0A%20%20%20%20%20*%20%40param%20title%0A%20%20%20%20%20*%20%40param%20author%0A%20%20%20%20%20*%20%40param%20publisher%0A%20%20%20%20%20*%20%40param%20pages%0A%20%20%20%20%20*%20%40param%20datePublished%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20BookFX(final%20String%20isbn%2C%20final%20String%20title%2C%20final%20String%20author%2C%20final%20String%20publisher%2C%20final%20int%20pages%2C%20final%20LocalDate%20datePublished)%20%7B%0A%20%20%20%20%20%20%20%20this.isbn%20%3D%20new%20SimpleStringProperty(isbn)%3B%0A%20%20%20%20%20%20%20%20this.title%20%3D%20new%20SimpleStringProperty(title)%3B%0A%20%20%20%20%20%20%20%20this.author%20%3D%20new%20SimpleStringProperty(author)%3B%0A%20%20%20%20%20%20%20%20this.publisher%20%3D%20new%20SimpleStringProperty(publisher)%3B%0A%20%20%20%20%20%20%20%20this.pages%20%3D%20new%20SimpleIntegerProperty(pages)%3B%0A%20%20%20%20%20%20%20%20this.datePublished%20%3D%20new%20SimpleObjectProperty%3C%3E(datePublished)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20String%20getIsbn()%20%7B%0A%20%20%20%20%20%20%20%20return%20isbn.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setIsbn(final%20String%20isbn)%20%7B%0A%20%20%20%20%20%20%20%20this.isbn.set(isbn)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20StringProperty%20isbnProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20isbn%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20String%20getTitle()%20%7B%0A%20%20%20%20%20%20%20%20return%20title.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setTitle(final%20String%20title)%20%7B%0A%20%20%20%20%20%20%20%20this.title.set(title)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20StringProperty%20titleProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20title%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20String%20getAuthor()%20%7B%0A%20%20%20%20%20%20%20%20return%20author.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setAuthor(final%20String%20author)%20%7B%0A%20%20%20%20%20%20%20%20this.author.set(author)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20StringProperty%20authorProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20author%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20String%20getPublisher()%20%7B%0A%20%20%20%20%20%20%20%20return%20publisher.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setPublisher(final%20String%20publisher)%20%7B%0A%20%20%20%20%20%20%20%20this.publisher.set(publisher)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20StringProperty%20publisherProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20publisher%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20int%20getPages()%20%7B%0A%20%20%20%20%20%20%20%20return%20pages.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setPages(final%20int%20pages)%20%7B%0A%20%20%20%20%20%20%20%20this.pages.set(pages)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20IntegerProperty%20pagesProperty()%20%7B%0A%20%20%20%20%20%20%20%20return%20pages%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20LocalDate%20getDatePublished()%20%7B%0A%20%20%20%20%20%20%20%20return%20datePublished.get()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20setDatePublished(final%20LocalDate%20datePublished)%20%7B%0A%20%20%20%20%20%20%20%20this.datePublished.set(datePublished)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20final%20ObjectProperty%3CLocalDate%3E%20datePublishedProprty()%20%7B%0A%20%20%20%20%20%20%20%20return%20datePublished%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20String%20toString()%20%7B%0A%20%20%20%20%20%20%20%20return%20%22Book%7B%22%20%2B%20%22isbn%3D%22%20%2B%20isbn.get()%20%2B%20%22%2C%20title%3D%22%20%2B%20title.get()%20%2B%20%22%2C%20author%3D%22%20%2B%20author.get()%20%2B%20%22%2C%20publisher%3D%22%20%2B%20publisher.get()%20%2B%20%22%2C%20pages%3D%22%20%2B%20pages.get()%20%2B%20%22%2C%20datePublished%3D%22%20%2B%20datePublished.get()%20%2B%20’%7D’%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20int%20hashCode()%20%7B%0A%20%20%20%20%20%20%20%20int%20hash%20%3D%207%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.isbn.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.title.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.author.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.publisher.get())%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20this.pages.get()%3B%0A%20%20%20%20%20%20%20%20hash%20%3D%2061%20*%20hash%20%2B%20Objects.hashCode(this.datePublished.get())%3B%0A%0A%20%20%20%20%20%20%20%20return%20hash%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20boolean%20equals(Object%20obj)%20%7B%0A%20%20%20%20%20%20%20%20if%20(this%20%3D%3D%20obj)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(obj%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(getClass()%20!%3D%20obj.getClass())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20final%20BookFX%20other%20%3D%20(BookFX)%20obj%3B%0A%20%20%20%20%20%20%20%20if%20(this.pages.get()%20!%3D%20other.pages.get())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.isbn.get()%2C%20other.isbn.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.title.get()%2C%20other.title.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.author.get()%2C%20other.author.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.publisher.get()%2C%20other.publisher.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(!Objects.equals(this.datePublished.get()%2C%20other.datePublished.get()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Natural%20comparison%20method%20for%20Title%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20book%0A%20%20%20%20%20*%20%40return%20negative%20value%2C%200%2C%20or%20positive%20value%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20int%20compareTo(BookFX%20book)%20%7B%0A%20%20%20%20%20%20%20%20return%20this.title.get().compareTo(book.title.get())%3B%0A%20%20%20%20%7D%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

The test program for this bean is almost identical to the original BeanTester but with the LocalDate added and used in a Comparator function.

[pastacode lang=”java” manual=”%2F%2F%20Required%20for%20Arrays.sort%0Aimport%20java.time.LocalDate%3B%0Aimport%20java.util.Arrays%3B%0A%2F%2F%20Required%20by%20the%20Comparator%20function%0Aimport%20static%20java.util.Comparator.comparing%3B%0A%0Apublic%20class%20BeanTesterFX%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Here%20is%20where%20I%20am%20testing%20my%20comparisons%0A%20%20%20%20%20*%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20void%20perform()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20Lets%20create%20four%20books%0A%20%20%20%20%20%20%20%20BookFX%20b0%20%3D%20new%20BookFX(%22200%22%2C%20%22Xenon%22%2C%20%22Hamilton%22%2C%20%22Harcourt%22%2C%2099%2C%20LocalDate.of(2017%2C%202%2C%204))%3B%0A%20%20%20%20%20%20%20%20BookFX%20b1%20%3D%20new%20BookFX(%22500%22%2C%20%22Boron%22%2C%20%22Bradbury%22%2C%20%22Prentice%22%2C%20108%2C%20LocalDate.of(2018%2C%205%2C%2023))%3B%0A%20%20%20%20%20%20%20%20BookFX%20b2%20%3D%20new%20BookFX(%22300%22%2C%20%22Radon%22%2C%20%22Heinlein%22%2C%20%22Thompson%22%2C%2098%2C%20LocalDate.of(2015%2C%208%2C%2030))%3B%0A%20%20%20%20%20%20%20%20BookFX%20b3%20%3D%20new%20BookFX(%22404%22%2C%20%22Argon%22%2C%20%22Campbell%22%2C%20%22Hachette%22%2C%20102%2C%20LocalDate.of(2012%2C%2011%2C%2015))%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Using%20Comparable%20to%20compare%20two%20books%0A%20%20%20%20%20%20%20%20System.out.println(%22Value%20returned%20by%20Comparable%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(b0.getTitle()%20%2B%20%22%20compared%20to%20%22%20%2B%20b1.getTitle()%20%2B%20%22%3A%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20b0.compareTo(b1))%3B%0A%20%20%20%20%20%20%20%20System.out.println()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Using%20Comparator%20to%20compare%20two%20books%0A%20%20%20%20%20%20%20%20System.out.println(%22Value%20returned%20by%20Comparator%22)%3B%0A%20%20%20%20%20%20%20%20BookPageComparatorFX%20bookPageComparatorFX%20%3D%20new%20BookPageComparatorFX()%3B%0A%20%20%20%20%20%20%20%20System.out.println(b0.getPages()%20%2B%20%22%20compared%20to%20%22%20%2B%20b1.getPages()%20%2B%20%22%3A%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20bookPageComparatorFX.compare(b0%2C%20b1))%3B%0A%20%20%20%20%20%20%20%20System.out.println()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Create%20an%20array%20we%20can%20sort%0A%20%20%20%20%20%20%20%20BookFX%5B%5D%20myBooks%20%3D%20new%20BookFX%5B4%5D%3B%0A%20%20%20%20%20%20%20%20myBooks%5B0%5D%20%3D%20b0%3B%0A%20%20%20%20%20%20%20%20myBooks%5B1%5D%20%3D%20b1%3B%0A%20%20%20%20%20%20%20%20myBooks%5B2%5D%20%3D%20b2%3B%0A%20%20%20%20%20%20%20%20myBooks%5B3%5D%20%3D%20b3%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22Unsorted%22)%3B%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22Sorted%20with%20Comparable%20Interface%20on%20Title%22)%3B%0A%20%20%20%20%20%20%20%20Arrays.sort(myBooks)%3B%20%2F%2F%20uses%20the%20Comparable%20compareTo%20in%20the%20bean%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22Sorted%20with%20Comparable%20Object%20on%20Pages%22)%3B%0A%20%20%20%20%20%20%20%20Arrays.sort(myBooks%2C%20bookPageComparatorFX)%3B%20%2F%2F%20uses%20the%20Comparator%20object%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22Sorted%20with%20Comparable%20lambda%20expression%20on%20Publishers%22)%3B%0A%20%20%20%20%20%20%20%20Arrays.sort(myBooks%2C%20(s1%2C%20s2)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20s1.getPublisher().compareTo(s2.getPublisher())%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%20%2F%2F%20uses%20the%20Comparator%20lambda%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22Sorted%20with%20Comparable%20lambda%20functions%20based%20on%20ISBN%22)%3B%0A%20%20%20%20%20%20%20%20Arrays.sort(myBooks%2C%20comparing(BookFX%3A%3AgetIsbn))%3B%20%2F%2F%20Comparable%20function%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22Sorted%20with%20Comparable%20lambda%20functions%20based%20on%20Date%20Published%22)%3B%0A%20%20%20%20%20%20%20%20Arrays.sort(myBooks%2C%20comparing(BookFX%3A%3AgetDatePublished))%3B%20%2F%2F%20Comparable%20function%0A%20%20%20%20%20%20%20%20displayBooks(myBooks)%3B%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Print%20the%20contents%20of%20each%20Book%20object%20in%20the%20array%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20theBooks%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20void%20displayBooks(BookFX%5B%5D%20theBooks)%20%7B%0A%20%20%20%20%20%20%20%20for%20(BookFX%20b%20%3A%20theBooks)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.print(b.getIsbn()%20%2B%20%22%5Ct%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.print(b.getTitle()%20%2B%20%22%5Ct%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.print(b.getAuthor()%20%2B%20%22%5Ct%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.print(b.getPublisher()%20%2B%20%22%5Ct%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(b.getPages()%20%2B%20%22%5Ct%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(b.getDatePublished())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Where%20it%20all%20begins%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20args%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20BeanTesterFX%20bt%20%3D%20new%20BeanTesterFX()%3B%0A%20%20%20%20%20%20%20%20bt.perform()%3B%0A%20%20%20%20%20%20%20%20System.exit(0)%3B%0A%20%20%20%20%7D%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

JavaFX does require that you use JavaFX beans as described here. They are only required if you intend to take advantage of binding to controls. If binding is not required then an ordinary Java bean should be used.

To summarize these two articles, if you are not using JavaFX then I expect you to use the Java bean class for data and models in the work you submit to me. In a JavaFX application I expect you to use the JavaFX bean whenever binding is required.

The #KFCStandard pom.xml file : UPDATE

      No Comments on The #KFCStandard pom.xml file : UPDATE

The following article was first published in August 2015. There are some minor updates since then so I am republishing the article here on my new blog domain.

The heart of a Maven managed project is the Project Object Model file named pom.xml. This determines what actions Maven will carry out. What follows is the pom file I require my students to use in their Software Development Project where they code a desktop application. Let’s look at this #KFCStandard pom.xml one section at a time.

[pastacode lang=”markup” manual=”%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Cproject%20xmlns%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%22%20%0A%20%20%20%20%20%20%20%20%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fmaven.apache.org%2Fxsd%2Fmaven-4.0.0.xsd%22%3E” message=”” highlight=”” provider=”manual”/]

The first line is the XML declaration. The W3C states that the current version of XML is 1.0. The encoding refers to the character set that is used in the document. UTF-8 is the most common form of encoding and it means that the document fully supports Unicode.

The next line contains the XML root tag named project. Following the tag are references to the namespace and schema used in the document. An XML validator uses this information to verify that the tags you use in the document are legal Maven pom tags.

[pastacode lang=”markup” manual=”%20%3CmodelVersion%3E4.0.0%3C%2FmodelVersion%3E” message=”” highlight=”” provider=”manual”/]

The modelVersion tag defines the version of the object model that the pom is using. It is required and as of Maven version 2.x it has been 4.0.0 and remains so for Maven 3.x.

[pastacode lang=”markup” manual=”%20%20%20%20%3CgroupId%3Ecom.kenfogel%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3EFXMavenDemo%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E1.0-SNAPSHOT%3C%2Fversion%3E” message=”” highlight=”” provider=”manual”/]

These three tags make up the GAV. The groupId, artifactId and version taken together represent the unique name for the project. When you look at the dependency section you will see these tags and Maven uses them to locate the libraries you may need to add to your code. If your code becomes a dependency for another project then this is how you will identify it.

The groupId tag typically defines a package name although it can be any string of characters. Most organizations will use their company’s domain name reversed for the groupId and as the first part of all the packages their developers create. The artifactId is typically the name of the project.

The version tag defines the current version of the project. Whatever you place here will be appended to the JAR file that Maven creates. You are free to use any versioning scheme that you want such as 1.0.0 or Best Version Ever Mark 2. A common convention in versioning is to include the string -SNAPSHOT to indicate a project under development.

[pastacode lang=”markup” manual=”%C2%A0%C2%A0%C2%A0%20%3Cpackaging%3Ejar%3C%2Fpackaging%3E” message=”” highlight=”” provider=”manual”/]

The packaging tag tells us the format of the file that will be built. The choices are jar, war and ear.

[pastacode lang=”markup” manual=”%C2%A0%C2%A0%C2%A0%20%3Cname%3EFXMavenDemo%3C%2Fname%3E%0A%20%20%20%20or%0A%20%20%20%20%3Cname%3E%24%7Bproject.artifactId%7D%3C%2Fname%3E” message=”” highlight=”” provider=”manual”/]

The optional name tag allows you to associate a name with the build. This name can contain any characters including spaces. If you do not have a name element Maven will use the artifactId. The second example just shows how the artifactId could be expressed by referring to the tag it was contained in.

[pastacode lang=”markup” manual=”%C2%A0%3Cdescription%3EA%20sample%20pom.xml%20file%20for%20this%20article%3C%2Fdescription%3E” message=”” highlight=”” provider=”manual”/]

The optional description tag lets you write any text that want to provide information to someone reading this file.

[pastacode lang=”markup” manual=”%20%20%20%20%3Cdevelopers%3E%0A%20%20%20%20%20%20%20%20%3Cdeveloper%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%3EEnter%20your%20school%20id%3C%2Fid%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cname%3EEnter%20your%20name%3C%2Fname%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cemail%3EEnter%20your%20email%20address%3C%2Femail%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdeveloper%3E%0A%20%20%20%20%3C%2Fdevelopers%3E%0A” message=”” highlight=”” provider=”manual”/]

The optional developers tag and its child tags allow you to identify the members of a project. I require my students to use this section to identify themselves.

[pastacode lang=”markup” manual=”%20%3Corganization%3E%0A%20%20%20%20%20%3Cname%3EEnter%20school%20name%3C%2Fname%3E%0A%20%3C%2Forganization%3E” message=”” highlight=”” provider=”manual”/]

The optional organization tag is used to identify the company that you work for. Historically it was required when delivering either applets or applications by means of the web but this is seldom done now for security reasons. If you are a student then the organization is the the school you are attending.

[pastacode lang=”markup” manual=”%20%20%20%20%3Cproperties%3E%0A%20%20%20%20%20%20%20%20%3Cproject.build.sourceEncoding%3EUTF-8%3C%2Fproject.build.sourceEncoding%3E%0A%20%20%20%20%20%20%20%20%3Cmaven.compiler.source%3E1.8%3C%2Fmaven.compiler.source%3E%0A%20%20%20%20%20%20%20%20%3Cmaven.compiler.target%3E1.8%3C%2Fmaven.compiler.target%3E%0A%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7Bproject.groupId%7D.MainApp%3C%2FmainClass%3E%0A%20%20%20%20%3C%2Fproperties%3E%0A” message=”” highlight=”” provider=”manual”/]

The properties section allows you to declare variables that can be used in later sections of the pom. The source encoding defines the character set that is used in the generated files produced by Maven.

Maven runs the Java compiler. The compiler source is the version of Java to use for compiling the code. Over the history of Java the format and organization of the class and jar files have changed. The target indicates what format you want for these files.

If the program is an executable for the desktop you can identify which class has the main method. This consists of the package and the class name. Here I am using the groupId as I use this as the root of all packages in a project. It can be any valid package name and class name in your project.

There are two cases in a pom where a plugin needs to know the full path to the class file that contains the main method. The exec plugin needs to know where to start the program when it runs. The shade plugin must list the main class in the jar’s MANIFEST.MF file.

[pastacode lang=”markup” manual=”%3Cdependencies%3E” message=”” highlight=”” provider=”manual”/]

The most significant function that Maven provides is the management of the required libraries for projects. Libraries must be in a project`s build path. This build path may outside the jar usually in the local Maven repository. The dependency jars can be included in the main jar and the contents of this jar is the build path.

In the dependencies section of a pom file you place a dependency block that must have the groupId, artifactId and version of a library you plan to use. When Maven process the pom file it will look for the files required for the dependency in the local Maven repository, the .m2 folder. If it’s not found here Maven will go online to the standard repository, maven.org, and use the information there to download the necessary files to .m2. If it cannot be found anywhere then an error will occur. Not every library can be located through maven.org so there is a repository tag that can be used in a pom if you wish to have Maven look in other online repositories. See http://bit.ly/1IlaoVx for more details on using multiple repositories.

[pastacode lang=”markup” manual=”%20%20%20%20%20%20%20%20%3C!–%20The%20dependency%20for%20the%20SLF4J%20Facade%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.slf4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Eslf4j-api%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E1.7.25%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3C!–%20Binding%20for%20Log4J%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-slf4j-impl%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3C!–%20Logging%20Framework%20Dependency%20Uses%20the%20log4j2%20library%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-api%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-core%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A” message=”” highlight=”” provider=”manual”/]

This first block of dependencies defines the logging library we will use. There are two parts to this particular logging approach. The first two dependency blocks define the SLF4J or Simple Logging Facade for Java. A façade is used to provide an interface for logging that is independent from the specific implementation of a logging framework. The second two dependency blocks define log4J as the logging implementation.

[pastacode lang=”markup” manual=”%20%20%20%20%20%20%20%20%3C!–%20JUnit%204%20testing%20dependency%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ejunit%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ejunit%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E4.12%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A” message=”” highlight=”” provider=”manual”/]

This is the dependency for the JUnit testing framework. It includes an additional tag named scope. A scope of tests means that this dependency is only used during the test phase of the build. The JUnit jar will not be included in the production jar.

From this point on you can add any additional dependencies that you may need.

[pastacode lang=”markup” manual=”%3Cdependency%3E%0A%20%20%20%3CgroupId%3Emysql%3C%2FgroupId%3E%0A%20%20%20%3CartifactId%3Emysql-connector-java%3C%2FartifactId%3E%0A%20%20%20%3Cversion%3E5.1.43%3C%2Fversion%3E%0A%3C%2Fdependency%3E” message=”” highlight=”” provider=”manual”/]

Students in my courses almost always need MySQL.

[pastacode lang=”markup” manual=”%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%3CgroupId%3Eorg.jodd%3C%2FgroupId%3E%0A%20%20%20%20%20%20%3CartifactId%3Ejodd-mail%3C%2FartifactId%3E%0A%20%20%20%20%20%20%3Cversion%3E3.8.6%3C%2Fversion%3E%0A%20%20%20%3C%2Fdependency%3E%0A” message=”” highlight=”” provider=”manual”/]

Students in my third year project course also need Jodd Mail.

[pastacode lang=”markup” manual=”%3C%2Fdependencies%3E” message=”” highlight=”” provider=”manual”/]

The dependencies are complete and now we move on to the build.

[pastacode lang=”markup” manual=”%3Cbuild%3E” message=”” highlight=”” provider=”manual”/]

The build section contains the information that Maven needs to compile, assemble and execute the project. Plugins that define operations that must be carried out in addition to the standard Maven tasks are listed here.

[pastacode lang=”markup” manual=”%3CdefaultGoal%3Eclean%20compile%20package%20exec%3Aexec%3C%2FdefaultGoal%3E” message=”” highlight=”” provider=”manual”/]

The default life cycle is made up of goals.The tag defaultGoal is used to define the Maven goals, sometimes also called phases. Goals are actions that Maven must carry out. Most IDEs allow you to declare the goals that you want in their run command. If you do that then it will override what you see here. In this tag I have the most common goals.

Clean deletes all class files and jar files. If you use clean then you must close any running instance of your project. Clean deletes the target folder. Your code is run from the target folder so it cannot be deleted if a process is running somewhere from the folder.

Compile does just that. If you do not use clean first then only source code files newer than their compiled class files will be compiled. For small projects clean is not an issue but in large systems you will not necessarily want to clean for every compile.

Package means to create the JAR file. All the class files produced by the compile goal are added to the jar file. The dependencies are also included in the package.

Exec means to execute the program. There are two flavours of exec, one is exec:java and the other is exec:exec. You must use one of these. The exec:exec runs the packaged jar as if it were being run from the command line and in a separate Java Virtual Machine from the IDE and Maven. This will fail if the dependencies are not in the jar.

The exec:java runs the program from the compiled class files and not the jar within the same JVM as the IDE. The Maven dependencies are in the build path so they are available to the executing code. The exec:exec gives a better picture of how your code will perform on its own. On a slow machine exec:java will execute faster because a new instance of the JVM is not needed.

[pastacode lang=”markup” manual=”%3Cplugins%3E” message=”” highlight=”” provider=”manual”/]

The plugins are the external components that carry out tasks that are not part of the default behaviour of Maven. These plugins are files that are retrieved from a repository for the use of Maven. They are stored in your local repository alongside the dependencies.

[pastacode lang=”markup” manual=”%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emaven-shade-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E3.0.0%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Eshade%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctransformers%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctransformer%20implementation%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22org.apache.maven.plugins.shade.resource.ManifestResourceTransformer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7BmainClass%7D%3C%2FmainClass%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Ftransformer%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Ftransformers%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A” message=”” highlight=”” provider=”manual”/]

This is the Shade plugin. It is responsible for creating an executable jar file. To be a standalone executable jar there are two changes that have to be made to a basic jar. The first is to include all the dependencies in the jar. The second is to create a text file called MANIFEST.MF in the META_INF folder in the jar that contains the name of the class where the main method is found. The execution of shade is defined in the executions tag to occur as part of the package phase when the plain jar is made. You will end up with two jars when this is done. The original and the executable. The following image gives you a sense of the difference between a plain jar and and an executable or shaded jar.

Image of the directory structure of a jar file.

The first jar in the image is the shaded jar and you ca see that all the dependencies are included in the jar. The second jar just contains the compiled code. This second jar will require that all the dependencies are already loaded into the computer and can be found in the build path. You can double click on a shaded jar to run it but not a regular jar to execute it.

[pastacode lang=”markup” manual=”%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.codehaus.mojo%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Eexec-maven-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E1.6.0%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%3Edefault-cli%3C%2Fid%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Eexec%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Ejava%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7BmainClass%7D%3C%2FmainClass%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutable%3E%24%7Bjava.home%7D%2Fbin%2Fjava%3C%2Fexecutable%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CcommandlineArgs%3E-jar%20%24%7Bproject.build.directory%7D%2F%24%7Bproject.build.finalName%7D.jar%3C%2FcommandlineArgs%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A” message=”” highlight=”” provider=”manual”/]

The exec plugin defines how the program will be run. As there are two ways to run a program, exec:exec and exec:java they are both defined here.

If you are using exec:java then the mainClass tag is used to identify which class file contains the main method.

If you are using exec:exec then the executable tag defines where the java virtual machine, either java.exe or javaw.exe, can be found. The commandlineArgs defines the command to run the executable jar in a separate JVM as if from the command line.

The values for all the $ values except ${mainClass}, that was defined in properties, are provided by the IDE. If you are not using an IDE then you will need to define these, such as ${java.home}, as an environment variable in the operating system.

[pastacode lang=”markup” manual=”%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emaven-surefire-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.20%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CargLine%3E-Dfile.encoding%3D%24%7Bproject.build.sourceEncoding%7D%3C%2FargLine%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CskipTests%3Efalse%3C%2FskipTests%3E%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A” message=”” highlight=”” provider=”manual”/]

The last plugin at the end of the pom file is Surefire. While Maven will run JUnit tests by default, this plugin writes the results of the test to a text file and an xml file. These results can also be seen in the console. The argLine element is required to eliminate a warning when the test are run. The configuration skipTests determines if the tests will execute are not. When set to true will ignore the tests. Use with caution as forgetting to set it back to false may result in delivering code you think works but really does not.

A complete pom follows. It is commented to remind you what each part is responsible for. This is the pom file my students must use in the work they do for me. If you want to learn more about the pom visit http://maven.apache.org/pom.html

[pastacode lang=”markup” manual=”%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Cproject%20xmlns%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%20http%3A%2F%2Fmaven.apache.org%2Fxsd%2Fmaven-4.0.0.xsd%22%3E%0A%0A%20%20%20%20%3C!–%20Maven%20version%20of%20the%20xml%20document%20currently%20only%204.0.0%20is%20valid%20–%3E%0A%20%20%20%20%3CmodelVersion%3E4.0.0%3C%2FmodelVersion%3E%0A%0A%20%20%20%20%3C!–%20The%20GAV%20consists%20of%20an%20arbitrary%20descriptor%20that%20is%20usually%20in%20the%0A%20%20%20%20form%20of%20a%20reverse%20domain%20name.%20–%3E%0A%20%20%20%20%3CgroupId%3Ecom.kfdesktopstandard%3C%2FgroupId%3E%0A%0A%20%20%20%20%3C!–%20This%20is%20the%20name%20given%20to%20the%20packaged%20build%20–%3E%0A%20%20%20%20%3CartifactId%3Ekf_desktop_standard_project%3C%2FartifactId%3E%0A%0A%20%20%20%20%3C!–%20The%20version%20of%20the%20build.%20Any%20value%20is%20valid%20though%20a%20number%20and%20a%0A%20%20%20%20string%20are%20common.%20SNAPSHOT%20means%20a%20project%20under%20development.%20FINAL%20or%20no%0A%20%20%20%20text%20is%20commonly%20used%20to%20refer%20to%20stable%20production%20version%20–%3E%0A%20%20%20%20%3Cversion%3E1.1-SNAPSHOT%3C%2Fversion%3E%0A%0A%20%20%20%20%3C!–%20Default%20value%20is%20jar%20but%20may%20be%20war%20or%20ear%20–%3E%0A%20%20%20%20%3Cpackaging%3Ejar%3C%2Fpackaging%3E%0A%0A%20%20%20%20%3C!–%20The%20name%20given%20to%20the%20project.%20Unlike%20groupId%20and%20artifactId%20a%20name%0A%20%20%20%20may%20have%20spaces.%20By%20default%20it%20is%20the%20following%20so%20it%20is%20optional%20–%3E%0A%20%20%20%20%3Cname%3E%24%7Bproject.artifactId%7D%3C%2Fname%3E%0A%0A%20%20%20%20%3C!–%20A%20description%20of%20the%20program%20–%3E%0A%20%20%20%20%3Cdescription%3EStandard%20starting%20point%20for%20JavaFX%20programs%20for%20students%20of%20Ken%20Fogel%0A%20%20%20%20%20%20%20%20that%20displays%20a%20table%20of%20data%20using%20JavaFX%20and%20JDBC%3C%2Fdescription%3E%0A%0A%20%20%20%20%3C!–%20Identifies%20the%20programmer%20or%20programmers%20who%20worked%20on%20the%20project%20–%3E%0A%20%20%20%20%3Cdevelopers%3E%0A%20%20%20%20%20%20%20%20%3Cdeveloper%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%3EEnter%20your%20school%20id%3C%2Fid%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cname%3EEnter%20your%20name%3C%2Fname%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cemail%3EEnter%20your%20email%20address%3C%2Femail%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdeveloper%3E%0A%20%20%20%20%3C%2Fdevelopers%3E%0A%0A%20%20%20%20%3C!–%20The%20company%20or%20organization%20that%20the%20programmer(s)%20work%20for%20–%3E%0A%20%20%20%20%3Corganization%3E%0A%20%20%20%20%20%20%20%20%3Cname%3EEnter%20school%20name%3C%2Fname%3E%0A%20%20%20%20%3C%2Forganization%3E%0A%0A%20%20%20%20%3C!–%20Global%20settings%20for%20the%20project.%20Settings%20can%20be%20accessed%20in%20the%20pom%0A%20%20%20%20by%20placing%20the%20tag%20name%20in%20%24%7B…%7D%20ex.%20%24%7BmainClass%7D%20–%3E%0A%20%20%20%20%3Cproperties%3E%0A%20%20%20%20%20%20%20%20%3Cproject.build.sourceEncoding%3EUTF-8%3C%2Fproject.build.sourceEncoding%3E%0A%20%20%20%20%20%20%20%20%3Cmaven.compiler.source%3E1.8%3C%2Fmaven.compiler.source%3E%0A%20%20%20%20%20%20%20%20%3Cmaven.compiler.target%3E1.8%3C%2Fmaven.compiler.target%3E%0A%0A%20%20%20%20%20%20%20%20%3C!–%20class%20that%20has%20the%20main%20method%20–%3E%0A%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7Bproject.groupId%7D.MainApp%3C%2FmainClass%3E%0A%20%20%20%20%3C%2Fproperties%3E%0A%0A%20%20%20%20%3Cdependencies%3E%0A%0A%20%20%20%20%20%20%20%20%3C!–%20The%20dependency%20for%20the%20SLF4J%20Facade%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.slf4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Eslf4j-api%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E1.7.25%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3C!–%20Binding%20for%20Log4J%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-slf4j-impl%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3C!–%20Logging%20Framework%20Dependency%20Uses%20the%20log4j2%20library%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-api%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.logging.log4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elog4j-core%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.8.2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3C!–%20JUnit%204%20testing%20dependency%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ejunit%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ejunit%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E4.12%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20only%20to%20be%20used%20during%20test%2C%20phase%20will%20not%20be%20included%20in%20executable%20jar%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3C!–%20MySQL%20dependency%20–%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Emysql%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emysql-connector-java%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E5.1.43%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%0A%20%20%20%20%3C%2Fdependencies%3E%0A%0A%20%20%20%20%3Cbuild%3E%0A%20%20%20%20%20%20%20%20%3C!–%20Goals%20may%20be%20set%20in%20the%20IDE%20or%20the%20pom%20IDE%20or%20CLI%20goals%20override%20the%0A%20%20%20%20%20%20%20%20defaultGoal%20–%3E%0A%20%20%20%20%20%20%20%20%3CdefaultGoal%3Eclean%20compile%20package%20exec%3Aexec%3C%2FdefaultGoal%3E%0A%0A%20%20%20%20%20%20%20%20%3C!–%20Plugins%20define%20components%20that%20perform%20actions%20–%3E%0A%20%20%20%20%20%20%20%20%3Cplugins%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20Shade%3A%20Create%20an%20executable%20jar%20containing%20all%20the%20dependencies%20when%0A%20%20%20%20%20%20%20%20%20%20%20%20the%20package%20goal%20is%20carried%20out%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emaven-shade-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E3.0.0%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Eshade%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctransformers%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctransformer%20implementation%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22org.apache.maven.plugins.shade.resource.ManifestResourceTransformer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7BmainClass%7D%3C%2FmainClass%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Ftransformer%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Ftransformers%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20Exec%3A%20Executes%20the%20program%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.codehaus.mojo%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Eexec-maven-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E1.6.0%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%3Edefault-cli%3C%2Fid%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20Runs%20in%20separate%20instance%20of%20JVM%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Eexec%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20Runs%20in%20same%20instance%20of%20the%20JVM%20as%20Maven%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Ejava%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–used%20by%20java%20goal%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–executes%20in%20the%20same%20VM%20that%20Maven%20runs%20in%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CmainClass%3E%24%7BmainClass%7D%3C%2FmainClass%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–used%20by%20exec%20goal%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!–runs%20in%20a%20separate%20VM%20from%20the%20one%20that%20Maven%20runs%20in%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexecutable%3E%24%7Bjava.home%7D%2Fbin%2Fjava%3C%2Fexecutable%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CcommandlineArgs%3E-jar%20%24%7Bproject.build.directory%7D%2F%24%7Bproject.build.finalName%7D.jar%3C%2FcommandlineArgs%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexecutions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!–%20Executes%20JUnit%20tests%20and%20writes%20the%20results%20as%20an%20xml%20and%0A%20%20%20%20%20%20%20%20%20%20%20%20txt%20file%20Test%20classes%20must%20include%20one%20of%20the%20following%20in%20their%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20Test*%20*Test%20*TestCase%20–%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emaven-surefire-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.20%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CargLine%3E-Dfile.encoding%3D%24%7Bproject.build.sourceEncoding%7D%3C%2FargLine%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CskipTests%3Efalse%3C%2FskipTests%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%0A%20%20%20%20%20%20%20%20%3C%2Fplugins%3E%0A%20%20%20%20%3C%2Fbuild%3E%0A%3C%2Fproject%3E%0A” message=”The Complete pom.xml” highlight=”” provider=”manual”/]