Skip to content

devon4j components

Cristian edited this page Mar 8, 2019 · 20 revisions

Components

devon4j Components

devon4j architecture

When working with devon4j the recommended approach for the design of the applications is the Component Oriented Design. Each component will represent a significant part (or feature) of our application related to CRUD operations. Internally, the components will be divided in three layers (service, logic, and dataaccess) and will communicate in two directions: service with database or, in the logic layer, a component with other component.

Principles

The benefits of dividing our application in components are:

devon4j component example

My Thai Star is an application of a restaurant that allows booking tables, and order different dishes so the main devon4j components are:

mythaistar components
  • dishmanagement: This component will manage the dishes information retrieving it from the db and serving it to the client. It also could be used to create new menus.

  • bookingmanagement: Manages the booking part of the application. With this component the users (anonymous/logged in) can create new reservations or cancel an existing reservation. The users with waiter role can see all scheduled reservations.

  • ordermanagement: This component handles the process to order dishes (related to reservations). A user (as a host or as a guest) can create orders (that contain dishes) or cancel an existing one. The users with waiter role can see all ordered orders.

  • usermanagement: Takes care of the User Profile management, allowing to create and update the data profiles.

Apart from that components we will have other packages for the cross-cutting concerns:

  • general: is a package that stores the common elements or configurations of the app, like security, cxf services or object mapping configurations.

  • imagemanagement: in case of functionalities that will be used in several components, instead of duplicate the functionality (code) we can extract it to a component that the other components will consume. In the case of the images, as both dishmanagement and usermanagement components are going to need to manage images, this imagecomponent will be used for that purpose.

  • mailservice: with this service we will provide the functionality for sending email notifications. This is a shared service between different app components such as bookingmanagement or ordercomponent.

devon4j component structure

The component will be formed by one package for each one of the three layers that are defined by the devon4j architecture: service, logic and dataaccess.

mythaistar component structure
  • Service Layer: will expose the REST api to exchange information with client applications.

  • Logic Layer: the layer in charge of hosting the business logic of the application.

  • Data Access Layer: the layer to communicate with the data base.

Apart from that the components will have a fourth package common.api to store the common elements that will be used by the different layers of the component. This is the place will contain common interfaces, constants, exceptions or enums.

devon4j component core

As we mentioned earlier, each component will be related to a functionality and this functionality will be represented in code by an Entity that will define all the properties needed to wrap the logic of that feature.

This Entity, that represents the core of the component, will be located in the dataaccess.api package.

The naming convention in devon4j for these entities is

[Target]Entity

The 'Target' should match the name of the related table in the data base, although this is not mandatory.

mythaistar component core1

Basically an Entity is simply a POJO that will be mapped to a table in the data base, and that reflects each table column with a suitable property.

mythaistar component core2

Create your components

After you have completed your own devon4j app creation, we are going to create our first app component.

Going back to our example application, Jump the Queue, we need to provide two basic functionalities:

  • register a user (returning an access code).

  • show the registered queue members.

To accomplish that we are going to work over three entities: Visitor, Queue and AccessCode.

visitor accesscode

The Visitor will be defined with: username, name, password, phoneNumber, acceptedCommercial , acceptedTerms and userType.

The Access Code will be represented as a ticketNumber, creationTime, startTime, endTime.

The Daily Queue will be defined with: name, logo, password, currentNumber, attentionTime , minAttentionTime, active and customers.

In addition, we will have to represent two relationships:

  1. The one to one relation between visitor and daily queue.

  2. The one to many relation between daily queue and access code.

Now is the moment to decide the components of our app. The complexity of the functionality would allow us to create only one component for managing the entities. But, in order to clarify the example, we are going to create also three components, one for Visitors, one for Access Codes and the last one for Daily Queue.

Note

However if you feel more comfortable managing the entities in a single component you can also do it in that way. The results will be the same and the only difference will be related with the structure of the elements and the distribution of the code.

The database

In the projects created with the devon4j archetype, we already have a complete data base schema that we can use as a model to create our own. By default we are going to work over the H2 database engine provided in the devon4j applications, although you can use other database alternatives for this exercise.

We have the /jtqj-core/src/main/resources/db/type/h2/V0001Create_Sequence.sql, V0002Create_RevInfo.sql and V0003Create_BinaryObject.sql these tables are already used by default so don’t delete them. We therefore also have /jtqj-core/src/main/resources/db/migration/1.0/V0004Add_blob_data.sql. You can create your own schema table that your required. For e.g. db/type/h2/V0005__Create_Visitor.sql.

Visitor table

Now we can add our first table Visitor in db/type/h2/V0005__Create_Visitor.sql. In the case of Jump the Queue, the visitors will provide: username, name, password, phoneNumber, acceptedCommercial and acceptedTerms to obtain an access code. So we need to represent that data in our table:

create table Visitor(
  id BIGINT NOT NULL AUTO_INCREMENT,
  modificationCounter INTEGER NOT NULL,
  username VARCHAR(255),
  name VARCHAR(255),
  password VARCHAR(255),
  phoneNumber VARCHAR(255),
  acceptedCommercial BOOL DEFAULT '0',
  acceptedTerms BOOL NOT NULL DEFAULT '0',
  userType BOOL DEFAULT '0',
  CONSTRAINT PK_Visitor PRIMARY KEY(id),
);
  • id: the id for each visitor.

  • modificationCounter: used internally by JPA to take care of the optimistic locking for us.

  • username: the visitor’s email.

  • name: the visitor’s name.

  • password: the visitor’s password.

  • phoneNumber: the visitor’s phone number.

  • accepterCommercial: boolean to know if the visitor has accepted commercial agreements.

  • accepterTerms: boolean to know if the visitor has accepted terms.

  • userType: the type of user.

Daily Queue table

As second table we will represent the Daily Queue that will be formed by name, logo, currentNumber, attentionTime, minAttentionTime, active and the customers. This table will be created at db/type/h2/V0006__Create_Queue.sql:

create table DailyQueue(
  id BIGINT NOT NULL AUTO_INCREMENT,
  modificationCounter INTEGER NOT NULL,
  name VARCHAR(255),
  logo VARCHAR(255),
  currentNumber VARCHAR(255),
  attentionTime TIMESTAMP,
  minAttentionTime TIMESTAMP NOT NULL DEFAULT '60000',
  active BOOL NOT NULL DEFAULT '1',
  customers INTEGER NOT NULL DEFAULT '0',
  CONSTRAINT PK_DailyQueue PRIMARY KEY(id),
);
  • id: the id for each visitor.

  • modificationCounter: used internally by JPA to take care of the optimistic locking for us.

  • name: the queue’s name.

  • logo: the queue’s logo.

  • currentNumber: the queue’s number being attended.

  • attentionTime: Average of time taken for each attended visitor.

  • minAttentionTime: Queue’s minimum attention time set by default.

  • active: boolean to know if the queue is active.

  • customer: the queue’s total number of customers.

Access Code table

As third table we will represent the Access Code that will be formed by the ticketNumber, creationTime, startTime and the endTime. This table will be created at db/type/h2/V0007__Create_Access_Code.sql

CREATE TABLE AccessCode(
  id BIGINT NOT NULL AUTO_INCREMENT,
  modificationCounter INTEGER NOT NULL,
  ticketNumber VARCHAR(5),
  creationTime TIMESTAMP,
  startTime TIMESTAMP,
  endTime TIMESTAMP,
  idVisitor BIGINT NOT NULL,
  idQueue BIGINT NOT NULL,
  CONSTRAINT PK_AccessCode PRIMARY KEY(id),
  CONSTRAINT FK_AccessCode_idVisitor FOREIGN KEY(idVisitor) REFERENCES Visitor(id),
  CONSTRAINT FK_AccessCode_idQueue FOREIGN KEY(idQueue) REFERENCES DailyQueue(id),
);
  • id: the id for each code.

  • modificationCounter: used internally by JPA to take care of the optimistic locking for us.

  • ticketNumber: the number of the ticket for a queue.

  • creationTime: the date related to the creation.

  • startTime: the date related to the start.

  • endTime: the date related to the end.

  • idVisitor: the relation with the Visitor entity.

  • idQueue: the relation with the DailyQueue entity.

Mock data

Finally we can provide a certain amount of mock data to start our app. Add a new sql script /jtqj-core/src/main/resources/db/migration/1.0/V0008__Master_data.sql adding sample data:

INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (0, 1, 'mike@mail.com', 'test', '1', '123456789', '0', '1', '1');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (1, 1, 'peter@mail.com', 'test', '1', '123456789', '1', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (2, 1, 'pablo@mail.com', 'test', '1', '123456789', '0', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (3, 1, 'test1@mail.com', 'test', '1', '123456789', '0', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (4, 1, 'test2@mail.com', 'test', '1', '123456789', '1', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (5, 1, 'test3@mail.com', 'test', '1', '123456789', '0', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (6, 1, 'test4@mail.com', 'test', '1', '123456789', '0', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (7, 1, 'test5@mail.com', 'test', '1', '123456789', '1', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (8, 1, 'test6@mail.com', 'test', '1', '123456789', '0', '1', '0');
INSERT INTO Visitor (id, modificationCounter, username, name, password, phoneNumber, acceptedCommercial, acceptedTerms, userType) VALUES (9, 1, 'test7@mail.com', 'test', '1', '123456789', '0', '1', '0');

INSERT INTO DailyQueue (id, modificationCounter, name, logo, currentNumber, attentionTime, minAttentionTime, active, customers) VALUES (1, 1, 'Day2', 'C:/logos/Day1Logo.png', 'Q001', NULL, '1970-01-01 00:01:00', TRUE, 9);

INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (1, 1, 'Q001', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, 1, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (2, 1, 'Q002', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 2, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (3, 1, 'Q003', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 3, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (4, 1, 'Q004', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 4, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (5, 1, 'Q005', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 5, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (6, 1, 'Q006', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 6, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (7, 1, 'Q007', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 7, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (8, 1, 'Q008', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 8, 1);
INSERT INTO AccessCode (id, modificationCounter, ticketNumber, creationTime, startTime, endTime, idVisitor, idQueue) VALUES (9, 1, 'Q009', CURRENT_TIMESTAMP, '2008-01-01 00:00:01', NULL, 9, 1);

The core of the components

Now that we have defined the data base for our entities is the moment to start creating the code of the related components.

We are going to use Cobigen to generate the component structure. That means that, as we already commented, we can generate all the structure and layers starting from a core element: a simple Plain Old Java Object that represents our Entity. So, in order to use Cobigen, we must create our entities in the expected location: MyEntitymanagement.dataaccess.api.

Visitor component

To implement the component we will need to define a VisitorEntity to connect and manage the data of the Visitor table in the data base.

The name for this component will be visitormanagement and for the entity VisitorEntity.

From the root package of the project create the following packages:

- visitormanagement
-- dataaccess
--- api
visitor component packages1
visitor component packages2

Now create a new java class in the just created visitormanagement.dataaccess.api package

visitor component entity1

and call it VisitorEntity

visitor component entity2

In the entity, we are going to add the fields to represent the data model, so our entity should contain:

	private String username;

	private String name;

	private String phoneNumber;

	private String password;

	private Boolean acceptedCommercial;

	private Boolean acceptedTerms;

	private Boolean userType;
Note

We are not adding the id nor the modificationCounter because Cobigen will solve this for us.

The AccessCodeEntity is throwing an error as it is not created yet. We will solve it in next step.

Now we need to declare our entity as a JPA entity with @Entity annotation (javax.persistence.Entity) at class level.

Also at class level, to map the entity with the database table, we will use the @Table annotation (javax.persistence.Table) defining the name of our already created Visitor table: @Table(name = "Visitor").

@Entity
@Table(name = "Visitor")
public class VisitorEntity

Now we have to declare the getters and setters of the fields of our entity. We can do it manually or using Eclipse with the option

visitor component gettersandsetters

The result of current implementation for VisitorEntity class is

package com.devonfw.application.jtqj.visitormanagement.dataaccess.api;

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "Visitor")
public class VisitorEntity{

	private String username;

	private String name;

	private String phoneNumber;

	private String password;

	private Boolean acceptedCommercial;

	private Boolean acceptedTerms;

	private Boolean userType;


	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the phoneNumber
	 */
	public String getPhoneNumber() {
		return phoneNumber;
	}

	/**
	 * @param phoneNumber the phoneNumber to set
	 */
	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the acceptedCommercial
	 */
	public Boolean getAcceptedCommercial() {
		return acceptedCommercial;
	}

	/**
	 * @param acceptedCommercial the acceptedCommercial to set
	 */
	public void setAcceptedCommercial(Boolean acceptedCommercial) {
		this.acceptedCommercial = acceptedCommercial;
	}

	/**
	 * @return the acceptedTerms
	 */
	public Boolean getAcceptedTerms() {
		return acceptedTerms;
	}

	/**
	 * @param acceptedTerms the acceptedTerms to set
	 */
	public void setAcceptedTerms(Boolean acceptedTerms) {
		this.acceptedTerms = acceptedTerms;
	}

	/**
	 * @return the userType
	 */
	public Boolean getUserType() {
		return userType;
	}

	/**
	 * @param userType the userType to set
	 */
	public void setUserType(Boolean userType) {
		this.userType = userType;
	}

}

AccessCode component

We are going to repeat the same process for the AccessCode component. So we will end up with the following structure

jumpthequeue emptycomponents

And the content of the AccessCodeEntity before start using Cobigen will be

package com.devonfw.application.jtqj.accesscodemanagement.dataaccess.api;

import java.sql.Timestamp;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.Size;

import com.devonfw.application.jtqj.visitormanagement.dataaccess.api.VisitorEntity;

@Entity
@Table(name = "AccessCode")
public class AccessCodeEntity {


	@Size(min = 2, max = 5)
	private String ticketNumber;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp creationTime;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp startTime;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp endTime;

	private VisitorEntity visitor;

	private QueueEntity queue;

	/**
	 * @return the ticketNumber
	 */
	public String getTicketNumber() {
		return ticketNumber;
	}

	/**
	 * @param ticketNumber the ticketNumber to set
	 */
	public void setTicketNumber(String ticketNumber) {
		this.ticketNumber = ticketNumber;
	}

	/**
	 * @return the creationTime
	 */
	public Timestamp getCreationTime() {
		return creationTime;
	}

	/**
	 * @param creationTime the creationTime to set
	 */
	public void setCreationTime(Timestamp creationTime) {
		this.creationTime = creationTime;
	}

	/**
	 * @return the startTime
	 */
	public Timestamp getStartTime() {
		return startTime;
	}

	/**
	 * @param startTime the startTime to set
	 */
	public void setStartTime(Timestamp startTime) {
		this.startTime = startTime;
	}

	/**
	 * @return the endTime
	 */
	public Timestamp getEndTime() {
		return endTime;
	}

	/**
	 * @param endTime the endTime to set
	 */
	public void setEndTime(Timestamp endTime) {
		this.endTime = endTime;
	}

	/**
	 * @return the visitor
	 */
	@OneToOne(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
	@JoinColumn(name = "idVisitor")
	public VisitorEntity getVisitor() {
		return visitor;
	}

	/**
	 * @param visitor the visitor to set
	 */
	public void setVisitor(VisitorEntity visitor) {
		this.visitor = visitor;
	}

	/**
	 * @return the queue
	 */
	@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
	@JoinColumn(name = "idQueue")
	public QueueEntity getQueue() {
		return queue;
	}

	/**
	 * @param queue the queue to set
	 */
	public void setQueue(QueueEntity queue) {
		this.queue = queue;
	}


}
Note

The compilation errors related to QueueEntity will be solved when we create the related entity in next step.

Queue component

Finally, we are going to repeat the same process for our last entity QueueEntity component. So we will end up with the following structure:

jumpthequeue emptycomponents2

And the content of the AccessCodeEntity before start using Cobigen will be

package com.devonfw.application.jtqj.queuemanagement.dataaccess.api;

import java.sql.Timestamp;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "DailyQueue")
public class QueueEntity {

	private String name;

	private String logo;

	private String currentNumber;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp attentionTime;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp minAttentionTime;

	private Boolean active;

	private int customers;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the logo
	 */
	public String getLogo() {
		return logo;
	}

	/**
	 * @param logo the logo to set
	 */
	public void setLogo(String logo) {
		this.logo = logo;
	}

	/**
	 * @return the currentNumber
	 */
	public String getCurrentNumber() {
		return currentNumber;
	}

	/**
	 * @param currentNumber the currentNumber to set
	 */
	public void setCurrentNumber(String currentNumber) {
		this.currentNumber = currentNumber;
	}

	/**
	 * @return the attentionTime
	 */
	public Timestamp getAttentionTime() {
		return attentionTime;
	}

	/**
	 * @param attentionTime the attentionTime to set
	 */
	public void setAttentionTime(Timestamp attentionTime) {
		this.attentionTime = attentionTime;
	}

	/**
	 * @return the minAttentionTime
	 */
	public Timestamp getMinAttentionTime() {
		return minAttentionTime;
	}

	/**
	 * @param minAttentionTime the minAttentionTime to set
	 */
	public void setMinAttentionTime(Timestamp minAttentionTime) {
		this.minAttentionTime = minAttentionTime;
	}

	/**
	 * @return the active
	 */
	public Boolean getActive() {
		return active;
	}

	/**
	 * @param active the active to set
	 */
	public void setActive(Boolean active) {
		this.active = active;
	}

	/**
	 * @return the customers
	 */
	public int getCustomers() {
		return customers;
	}

	/**
	 * @param customers the customers to set
	 */
	public void setCustomers(int customers) {
		this.customers = customers;
	}
}

With this we have finished preparing the core of our components. Now we can start using Cobigen to generate all the remaining structure (services, layers, dao’s, etc.).

Note

Now we can solve the compilation errors related to QueueEntity in the AccessCodeEntity.java class.

The component’s structure with Cobigen

Once we have finished creating the core of our components we could continue creating all the structure and elements manually, but we are going to show how using Cobigen for those tasks we can save a significant amount of time and effort.

Cobigen Health Check

The first time we use Cobigen is recommended to check the health of the tool. To do so, right-click over an entity and select Health Check

cobigen0

The next dialogs will show us if there are outdated templates. In that case we can solve it clicking the Update button.

cobigen health1
cobigen health2

Queue component structure (Entity without relations)

In order to create the whole structure of a component with Cobigen we only need to right-clicking over our component core entity, select Cobigen > Generate

cobigen1

Now we have to choose which packages we want to generate with the tool.

The options are:

  • CRUD SpringData Repository: generates the entity repository(that contains the CRUD operations) in the data access layer.

cobigen2 crud springdata repository
  • CRUD REST services: generates a complete service layer with CRUD operations for our entity exposed as a REST service.

cobigen2 crud rest services
  • CRUD UC logic: generates the logic layer dividing the implementation in different use cases.

cobigen2 crud uc logic
  • Entity infrastructure: creates the entity main interface and edits (by a merge) the current entity to extend the devon classes

cobigen2 entity infrastructure
  • TO’s: generates the related Transfer Objects, that we will explain in next chapters of this tutorial

cobigen2 to

To generate all the needed functionalities of our component we are going to select the following packages to be generated at the same time

cobigen3 allpackages

Now we can select the fields to be involved (all by default) or directly create all the packages clicking the Finish button.

During the process Cobigen will show a message asking us to review some ambiguous references. Click Continue

cobigen4 review imports

Once Cobigen has finished we will check if we need to introduce manual adjustments.

First, we need to adjust manually some imports related to Timestamp in:

API

  • queuemanagement.common.api.Queue

  • queuemanagement.logic.api.to.QueueEto

  • queuemanagement.logic.api.to.QueueSearchCriteriaTo

CORE

  • queuemanagement.dataaccess.api.repo.QueueRepository

  • queuemanagement.dataaccess.api.QueueEntity

We can fix the errors by manual importing ´java.sql.TimeStamp´:

cobigen5 manual import

AccessCode component structure (Entity with relations)

We repeat the process with AccessCode but in this case, since its an entity with relations, we are going to have to select different cobigen options:

cobigen3 allpackages cto

After letting cobigen finish generating and fixing the imports like in the last step there will be some errors left, this is because we have a relation (dependency) with some of the Queue and Visitor component elements, that are still not created. We will solve this compilation errors in next steps.

cobigen6 expected errors

Visitor component structure (Entity without relations)

Finally we are going to repeat the same process that was used with the Queue component but this time, using Cobigen with our other Visitor component. Once cobigen has finished we can fix one of the compilation error in AccessCodeCto and UcFindAccessCodeImpl related to VisitorEto by manual importing like we learned in the last step.

Run the app

If all compilation errors are solved run the app ( SpringBootApp.java right click > Run as > Java application ). The app should be launched without errors.

Congratulations you have created your first devon4j components. In the next chapter we will explain and show in detail each of the created elements