×
Back to book

SpringBot File Structure

The file structure which is used in SpringBot applications

Almost all files written by the bot are inferred from the model itself, with some exceptions where it is more useful to abstract a lot of things into their own standalone components.

Server-Side Directory Structure

See below for the current project structure with simple descriptions.

Source - Top Level Package (src/main/java/com/springbot/basic)

.
├── configs
│   └── security
│       ├── auditing
│       │   ├── entities
│       │   ├── repositories
│       │   └── services
│       ├── authorities
│       ├── evaluators
│       ├── expressions
│       ├── filters
│       ├── helpers
│       ├── meta
│       ├── repositories
│       └── services
├── controllers
├── deserializers
├── entities
│   └── listeners
├── graphql
│   └── resolvers
│       ├── mutation
│       └── query
├── lib
│   ├── graphql
│   │   └── errors
│   └── services
│       └── email
├── repositories
├── serializers
└── services
Package Purpose
configs All application configuration is found here. This includes any overriding or new config such as security.
configs.security Security config
controllers All application controllers, primarily used for all REST API endpoints.
deserializers Custom deserializers for the result of each of the controllers. Overrides the default Spring deserializers. These are only used for the REST controllers.
entities Annotated entities; these represent the data structures present in the application.
entities.listeners Listeners to allow actions to be performed pre-post fetch/save etc.
graphql GraphQL configuration, including mutations queries and utils among other graphql specific classes.
lib Helpers and services that don't fall in the above or below packages.
repositories JPA repositories, these work similar to a DAO (Data access object) and act as the interface between the database and the entities.
serializers Custom serializers for the result of each of the controllers. Overrides the default Spring serializers.
services Services for the application.

Entities

Contains files to declare our entity classes from the Entity Diagram.
If you have a look at an entity, you will see that they heavily use annotations to set up constructors, getters, setters, and database mappings that would normally be done with a fair amount of boilerplate code.

All entities extend AbstractEntity, which can also be found in this package.
AbstractEntity contains the following attributes:

  • UUID
  • created date
  • modified date time
  • UUID modifiedBy (which user last modified the entity)
  • UUID createdBy (which user created the entity)

Each attribute in the class will have several annotations. Here is an example:

@ApiModelProperty(notes = "The Identifications that are related to this entity.")
    @OneToMany(mappedBy = "accreditedParty", cascade = {CascadeType.MERGE}, fetch = FetchType.LAZY)
    @NotEmpty(message = "Identification is required")
    private Set<IdentificationEntity> identifications = new HashSet<>();
  • API Model Property only used for Swagger API docs - This takes doco description from the attribute in your Entity Diagram
  • OneToMany - describes the type of relationship (if the attribute is a related entity). We recommend this Baeldung article to learn more about relationship types.
  • NotEmpty - validation - this can be set by adding validators to your attributes in the entity model. This will prevent entities being saved to the database if this field is not set. It will return the error message through the API.

The rest of the class is custom getters, setters, and functions to add or remove related entities from this entities list of relationships.
E.g.:

    public void addIdentification(IdentificationEntity identification) {
        addIdentification(identification, true);
    }

    public void addIdentification(@NonNull IdentificationEntity identification, boolean doReverseAdd) {
        if (!identifications.contains(identification)) {
            identifications.add(identification);
            if (doReverseAdd) {
                identification.setAccreditedParty(this, false);
            }
        }
    }

    public void setIdentifications(Set<IdentificationEntity> identifications) {
        setIdentifications(identifications, true);
    }

    public void setIdentifications(Set<IdentificationEntity> identifications, boolean doReverseAdd) {
        this.identifications.forEach(IdentificationEntity::unsetAccreditedParty);
        this.identifications = identifications;

        if (doReverseAdd) {
            this.identifications.forEach(identificationEntity -> identificationEntity.setAccreditedParty(this, false));
        }
    }
    public void removeIdentification(IdentificationEntity identification) {
        this.identifications.remove(identification);
    }

    public void unsetIdentifications() {
        this.identifications.forEach(IdentificationEntity::unsetAccreditedParty);
        this.identifications.clear();
    }

The entities package also contains some sub-packages:

  • enums -simple enumerated entities which have literal values SCREAMING_CASE, as defined in the Entity Diagram. The enumerated have a literal string value which is used for display and readability purposes. In the database, these enumerated keys are stored as Integer values.

  • Listeners - triggers that are called before and after persistence and fetch and allow for things to be altered before they are saved and after they are queries.

  • Specifications - rarely used but is a place for custom GraphQL configuration.

graphql

This package contains the logic to resolve all GraphQL requests sent to the server-side.
serverside/src/main/java/applicationName/graphql

.
└── src/main/java/applicationName
    └── graphql
        ├──resolvers
        │       ├── mutation
        │       └── query
        ├── utils
        ├── CustomGraphQLErrorHandler
        └── GraphQLCombiner

Graphqlcombiner is the top level resolvers, which is made up of the resolvers found in the resolvers package.

For more information please see the documentation for GraphQL Java.

Resources (src/main/resources)

.
├── graphql
│       └── schemas
├── logback
├── static
└── application
          └── properties

graphql.schemas

Contains GraphQL files which declare JSON structure of our Entities from our Entity Diagram.

These schemas define what queries and mutations our GraphQL API supports.

For more information, please refer to the Java GraphQL library.

logback

Contains settings to change how our logging platform of choice works. In this file, you can set the max file size of the logs or the file name pattern. To make changes to this file remember to turn on the protected region

static

Static is where client-side applications will be stored. If you want to serve a client-side from your server-side, you can compile our client-side application and put it inside the static folder. When you run the server-side and navigate to it, it will try to serve any index.html that is stored inside the static folder.

application.properties

These property files contain properties for the corresponding environment e.g: application-dev for development.

This is where you define login info for your database. By default you will have something like the following in your application-dev.properties:

# % protected region % [Customise your connection details here] off begin
spring.datasource.url=${DATA_SOURCE_URL:jdbc:postgresql://localhost:5432/postgres}
spring.datasource.username=${DATA_SOURCE_USERNAME:user}
spring.datasource.password=${DATA_SOURCE_PASSWORD:}
spring.datasource.platform=postgres
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=${HIBERNATE_DDL:update}
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
springfox.documentation.swagger.v2.host=localhost:8080
graphiql.cdn.enabled=true
voyager.cdn.enabled=true
altair.cdn.enabled=true
# % protected region % [Customise your connection details here] end

To be able to run your server-side application you will need to either set up PostgreSQL and ports to match the default settings in this file, or pass in environment variables in your run configuration to override them.
e.g: export DATA_SOURCE_URL=jdbc:postgresql://localhost:5432/applicationName

Client-Side Structure

.
└── src
    ├── app
    │   ├── admin
    │   │   ├── pages
    │   │   └── tiles
    │   ├── enums
    │   ├── frontend
    │   ├── lib
    │   │   ├── components
    │   │   ├── directives
    │   │   ├── enums
    │   │   ├── guards
    │   │   ├── interceptors
    │   │   ├── models
    │   │   ├── pipes
    │   │   ├── routing
    │   │   ├── scss
    │   │   ├── services
    │   │   ├── tiles
    │   │   └── utils
    │   ├── models
    │   │   └── ...
    │   ├── pages
    │   │   └── ...
    │   ├── services
    │   │   └── ...
    │   ├── tiles
    │   │   ├── crud
    │   │   └── custom
    │   └── views
    │       ├── ...
    ├── assets
    │   ├── fonts
    │   └── img
    └── environments
Package Purpose
src.app.admin Container for the admin section. This contains all admin pages and components.
src.app.admin.pages All admin pages and their associated routes.
src.app.admin.tiles All admin tiles.
src.app.admin.tiles.crud Admin CRUD (Create, Read, Update and Delete) tiles.
src.app.admin.tiles.crudDashboard Admin Dashboard tile.
src.app.enums Enumerated values that have been modelled for the application. These are application specific enums based on the Entity Diagram.
src.app.frontend Core frontend component that wraps the entire frontend of the application. All components that belong to the frontend are contained within this core component. Common frontend elements such as navigation can be found here.
src.app.lib Shared components and utils.
src.app.lib.components Common application components; these are mostly elements such as the date picker etc.
src.app.lib.directives Shared directives used within the application. See Directive for more details.
src.app.lib.enums Common global enums that are required by every application.
src.app.lib.guards Guards to manage route access, see Routing and Navigation for more details.
src.app.lib.intercepters Intercepters used globally within the application, see HttpIntercepter for more details.
src.app.lib.models Common models used by every application.
src.app.lib.pipes Common pipes available to be used in the application. See Pipes for more details.
src.app.lib.routing Constructs used to assist in routing. See Routing and Navigation for more details.
src.app.lib.scss SCSS files that can be used to customise the application. Without customisation, these will simply default to Harmony styling.
src.app.lib.tiles Core tiles that every application will require. Found among these can be login, logout etc.
src.app.lib.utils Common utils. Data factories can be found here.
src.app.models Models for all objects in the application, these models also contain state management classes such as reducers, selectors, effects, and actions each given model. These are application specific and are based on the Entity Diagram.
src.app.pages Pages as modelled in the UX Diagram.
src.app.services Services for each of the objects in the application. These are application specific and are based on the Entity Diagram.
src.app.tiles Tiles as modelled in the UX Diagram.
src.app.tiles.crud CRUD (Create, Read, Update, Delete) tiles, if they have been added to the UX Diagram.
src.app.tiles.crud.custom Custom tiles, if they have been added to the UX Diagram.
src.app.views Views as modelled in the UX Diagram.
src.assets.font Application fonts.
src.assets.img Application images.
src.environments Environment settings; these are different for dev and beta.

Test Target Structure

The Java testing framework is driven by a collection of libraries that aid conducting unit tests, API tests, and integration tests. The integration testing is primarily written through the Selenium library and Cucumber framework to ensure user acceptance criteria are achieved and written in a logical language that is understandable by non- techies. The unit testing and API testing is conducted through the in-built Spring Boot testing framework.

(src/main/test)

.
├── feature
├── stepdefs
├── shared
├── managers
├── runners
├── configuration
└── pom
Package Purpose
feature All feature files are located here.
stepdefs All step definitions for the feature files
shared The test context as well as all other configuration and setup logic
managers Managers are classess that adopt the mediator pattern to extract all complex functionality of the testing framework to their respective managers.
configuration Configuration classes are used to import configuration files from the resources directory. this directory also contains helper classes and methods that aid in importing these files and configurating the testing framework.
pom All custom wrappers for web elements and their configuration are located here .
runners Runners are the entry point of the testing target. There are pre-defined suite runners for active developement, production deployment, and more, which define the set of tests that should be run.

AsSuite of feature files, step definitions, and page object models will be bot-written for all applications for common web components and application processes. These include login and logout, entity CRUD, user CRUD, navigation, and others.

Some of these bot-written tests may or may not be relevant to the system under testing. For that reason, all Cucumber tests have been tagged with @skip and by default will not be executed by the test runners. To ensure they are run if they are relevant to the application, remove this tag from their scenario.

(src/main/resources)

.
├── output
│   ├── uat
│   └── screenshot
└── config
Package Purpose
output All files that are out putted from the testing target should be located here. This includes uat videos for tagged tests and screen shots for failed tests and more.
config All configuration arguments are specified within their respective configuration file and placed here. This allows users to tweak their testing environment by simply adding a key-value pair.

Application Properties

Application properties can be found under serverside/src/main/resources. Here we have the various profiles that can be run as well as the default properties that are included in every profile.

Most of the properties that need to be changed can be done via environment variables. The following are available to be changed in this manner,

  • DATA_SOURCE_URL - Your database connection string
  • DATA_SOURCE_USERNAME - Your database username
  • DATA_SOURCE_PASSWORD - The password to access your database,
  • HIBERNATE_DDL - (Default to update) See Initialize a Database Using Hibernate for the available options and what they mean.

For the options that cannot be set in this manner, you can edit the files directly by first activating the protected regions.

You can also save in a file called env.sh and source it with source env.sh to simplify the process.