Top Menu

Jump to content
Home
    Modules
      • Projects
      • Activity
      • Work packages
      • Gantt charts
      • News
    • Getting started
    • Introduction video
      Welcome to Wiki
      Get a quick overview of project management and team collaboration with OpenProject. You can restart this video from the help menu.

    • Help and support
    • Upgrade to Enterprise edition
    • User guides
    • Videos
    • Shortcuts
    • Community forum
    • Enterprise support

    • Additional resources
    • Data privacy and security policy
    • Digital accessibility (DE)
    • OpenProject website
    • Security alerts / Newsletter
    • OpenProject blog
    • Release notes
    • Report a bug
    • Development roadmap
    • Add and edit translations
    • API documentation
  • Sign in
      Forgot your password?

Side Menu

  • Overview
  • Activity
    Activity
  • News
  • Forums
  • 00 - Business Architecture
    00 - Business Architecture
  • 01 - Software Architecture Document (SAD)
    01 - Software Architecture Document (SAD)
  • 02 - Developer's Cookbook
    02 - Developer's Cookbook
  • 03 - REST Resource Design
    03 - REST Resource Design
  • 04 - Installation Notes
    04 - Installation Notes
  • 05 - Support
    05 - Support

Content

You are here:
  1. 02 - Developer's Cookbook
  2. 02.01 - Development

02.01 - Development

  • More
    • Print
    • Table of contents

[D10] Support of Java8 Optional in API methods

The use of java.util.Optional within API methods makes it easy to translate 404-Not Found into Optional.empty(). Without this pretty cool Spring & Jackson feature we must live with an null response object, that you might have seen at some point. Not the instance is null, but all fields of the instance are, because the sender (a Spring Boot app) sends a JSON response with http status == 404 but passes a ResponseBody, and that one is tried to be deserialised into a business object, therefor all fields of the business object are null.

[D9] Maven Dependency Declaration & Usage

Apache Maven build tool knows about a dependencies section and a dependencyManagement section.

Rule We declare dependencies with their version and classifiers but without scope within the dependencyManagement section and actually define the usage of the dependency within the dependencies section without the version but with the proper scope. It is not allowed to declare and define the usage in the dependencies section only.

[D8] Explicit database columns

Issue As we do with JSON properties in [D2] Use JsonProperty explicit we should also be explicit and name every database column. Without doing so we could run into trouble when we refactor field names but don’t want the columns to be renamed.

Rule Instead of ending with a mix of annotated and un-annotated fields, all the fields that are going to be mapped onto database columns, need to be annotated with @Column and a name must be set. The name must have the prefix C_ assigned. This is very handy to avoid cases where the Java names clashes with database keywords. For example: One could name a field user that ends in a column USER that is a keyword in RDBMS and forbidden to use. To avoid such clashes all columns have the C_ prefix.

[D7] Define a Logger

Issue To simply define a Logger instance just use a static definition and don’t add some magic third party library like Project Lombok.

Example

private static final Logger LOGGER = LoggerFactory.getLogger(MyClazz.class);

This is simple, added fast and just uses Java and the logging library of choice. This line of code can be created with an IntelliJ live template dlog (define logger).

Convention - Always use slf4j as log API - Logger instances must be private to the class and static - Logger instances in OpenWMS.org code must be named as LOGGER

[D6] Direction of mapping between models

Issue In OpenWMS.org we have at least two or more domain models that needs to be mapped from one into the other. The inner business domain model of a microservice is often also the persistence model and thats fine. But outer public API have their own representation, i.e. domain model, like the VO model of the presentation of the MO model of the messaging layer. We could map in bidirectional way that makes often sense but sometime it only make sense to make in one direction.

Problem Our mapping library support the configuration of the mapping direction on attribute level but only with two options: bi-directional or one-way. The latter means from source (class-a) to destination (class-b). A explicit switch, like a-b or b-a does not exist.

Solution So we define that we always name the inner model as class-a and the outer model as class-b. By this convention it is clearly defined that we map between the rich domain model to the more simple domain model without object-graph resolution, just by traversing the source object and dereference the attribute of the destination class.

Example Here an correct example of a mapping from the inner class to the outer class:

<mapping>

    <class-a>org.openwms...ReceivingOrderPosition</class-a>

    <class-b>org.openwms...ReceivingOrderPositionVO</class-b>

    <field type="one-way">

        <a is-accessible="true">product.sku</a>

        <b is-accessible="true">sku</b>

    </field>

</mapping>

[D5] Get Feign work with PATCH

Issue Out of the box a FeignClient does not support HTTP PATCH requests.

Solution To get PATCH work with Feign another Maven dependencies needs to be added:

<dependency>

    <groupId>io.github.openfeign</groupId>

    <artifactId>feign-httpclient</artifactId>

    <version>10.4.0</version>

</dependency>

The correct version mut be used, that works with OpenFeign.

[D4] Give database constraints an explicit name

For better maintenance use clear and unique names for unique constraints and foreign keys:

@UniqueConstraint(name = "UC_LOC_ID", ...)

@ForeignKey(name = "FK_LOC_ACC")

Unique constraints start with UC, then the abbreviation for the hosting table and an identifier. Foreign keys start with FK, then the abbreviation for the hosting table and the referenced table/column.

[D3] (Optional) Use constants as JPA Table names

Example:

@Entity

@Table(name = Location.TABLE)

class Location {

    public static final String TABLE = "COM_LOCATION";

}

In case of refactoring the table name change can be done at one single place. In native queries the constant can be referenced instead of a String.

[D2] Use JsonProperty explicit

In classes serialized as JSON use @JsonProperty on properties explicitly. This ensures that refactoring and renaming the fields keeps the JSON names and the API stable.

[D1] Exception translation in REST Controller

Issue Java Exceptions should be translated into proper representations at the system boundary. @RestController and @Controller classes must translate exceptions into proper JSON structures (XML is not in focus).

Solution In order to implement Spring @ExceptionHandler or ControllerAdvice in every controller take advantage of a set of those by extending the class org.openwms.core.http.AbstractWebController. Own exception classes and those of the ameba-lib library are translated properly.

Loading...