Loading...

Follow dev cases | Java development tutorials on Feedspot

Continue with Google
Continue with Facebook
or

Valid

There are cases, when we try to use library with a higher supported version of Java than our application and as a result we get an exception like this:

java.lang.UnsupportedClassVersionError: TestedClass :
 Unsupported major.minor version 52.0
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(Unknown Source)

or like that:

bad class file: TestedClass
class file has wrong version 55.0, should be 52.0
Please remove or make sure it appears in the correct subdirectory of the classpath.

Unfortunately, Java bytecode compiled on higher Java version isn’t compatible with older versions – you can’t run new code on old JVM.

How to identify compiled Java version

You can find out information about compiled Java version of conflicted class by running the following command:

 javap -verbose package.TestedClass

The javap disassembles provided class and prints its declarations of the non-private members. The output also contain compilation details, like version of Java used to compile:

minor version: 0
major version: 50

In case you don’t have available JDK to run javap, you can check the .class file manually. The information is stored in the file at the 7th byte. On Linux you can view file contents (in decimal byte values) using the command:

od -t u1 TheClass.class

The table below contains mapping of major version to JDK version

JVMMajor version
Java 1.1 45
Java 1.2 46
Java 1.3 47
Java 1.448
Java 549
Java 650
Java 751
Java 852
Java 953
Java 1054
Java 1155
Java 12 56
Java 1357
Java 1458
Solution

When you have information about Java version incompatibilities, there are two possible solutions:

Downgrading the library to lower version

If you are the owner of the dependency and the library is compatible with lower version of Java (there aren’t used any new features of newer specification) you can compile the library with older Java.

Upgrading the application to higher version

Upgrading your own application to the library version may be the best option. But in this case you should also be careful – you should check whether other dependencies are also compatible with the newer Java version.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Table per class is one of three strategies in JPA that persist Java domain model into relational database. It is the least used one than others. Let’s find out why this strategy is avoided, even ifits features may be useful in some cases.

Model

Here are Java classes with JPA mappings:

@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String name;
 
    //Getters and setters
} 
@Entity
public class Car extends Product {
    private int brand;
    private int model; 
} 
@Entity
public class Toy extends Product {
    private int minimalAge;
}  

We must explicitly define the strategy in @Inheritance annotation at the root entity, because the default is Single Table strategy (described here). And this is the only information which we should provide – the strategy don’t need a discriminator column, subclasses don’t need any specific configuration – even setting discriminator values by the @DiscriminatorValue annotation.

Similarly to the Joined Strategy (desribed here), each non abstract class of the hierarchy gives its own table. But the table of the corresponding entity contains all the fields of this entity, including the inherited ones. All tables are independent – there are no foreign keys between them. In our example, we get three tables: PRODUCT (with columns: ID, NAME), CAR (with columns: ID, NAME, BRAND, MODEL), and TOY (with columns: ID, NAME, MINIMALAGE). As a consequence, the tables don’t need to store discriminator values.

To instantiate a particular entity, we have to query only one table.

Pros

The strategy offers good performane when querying single entities – we have all the data in one table, we don’t need any joins.

Having individual table per entity allows us to define specyfic constraints at the database level to control data integrity.

Cons

The main drawback of the strategy is the fact we can’t use polimorphic queries efficiently. When querying parent entities, we have to use UNION statements to gather data from all tables.

Another aspect is that data in tables are not normalized – the same information can be stored in different tables. Controling the same logic of data integrity together in many tables can be error prone.

Especially defining relationships of the entities can be very confusing – imagine our appliaction has the following entity:

@Entity
public class Customer extends Product {
    @Id
    @GeneratedValue
    private Long id;
    private Product product;
} 

We can’t efficiently define foreign key constraint (from customer to product) at the database level, beacuse foreign key can’t point to more than one table. The only solution is not to define such key and control data only at the application level. We don’t recommend this solution – it can lead to loss of data integrity

Furthermore, although the Table Per Class strategy is part of the JPA , the support for this startegy is optional – providers aren’t forced to implement this solution. As a consequence, the solution based on this strategy isn’t portable.

Summary

As we can see, the Table Per Class strategy have more disadvantages than advantages. It makes it difficult for us to control data integrity at the database level, performance of polymorphic queries can be really low and our solution isn’t portable across different JPA providers. so, when we develop application that is changing dynamically, the Table Per Class should’t be chosen.

But there can be some cases, when this strategy is the best choice – when the Java model isn’t complicated (for example subclasses doesn’t share common fields and have different characteristics) and we are sure the will be no modifications of the entities hierarchy, we can choose this strategy as the most efficient.


  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Joined Table is one of three strategies in JPA dealing with persisting Java domain model into relational database. The main point of this strategy is that each class of the hierarchy have its own table. Let’s check how to use this strategy and what are the consequences of using this solution.

Model

Here are Java classes with JPA mappings:

@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name="type") 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    //Getters and setters
} 
@Entity
@DiscriminatorValue("Car") 
public class Car extends Product {
    private int brand;
    private int model; 
} 
@Entity
public class Toy extends Product {
    private int minimalAge;
}  

We must explicitly define the strategy in @Inheritance annotation at the root entity, because the default is Single Table strategy (described here). Subclasses don’t need any specific configuration – if we don’t want to use default discriminator values, we can customize them using @DiscriminatorValue annotation.

The behavior of this strategy is very intuitive – each class of the hierarchy gives its own table. Each table contains only the primary key of the entity and fields of this corresponding class. To instantiate a particular entity, we have to query all the tables that exist in the hierarchy of this entity. Only the root table contains additional column with discriminator value – based on this information we know which tables we must to query.

Pros

From the point of view of the database, the Joined inheritance strategy is is the most consistent of all three strategies – there are no redundancy in data persistence. We can define not null checks and other constraints on all the columns to control data integrity at the database level.

The fact that we don’t have nullable columns while persisting entity (like in Single Table strategy ) has the positive impact on the amount of memory used by the database – the database use the minimum amount of memory needed to store entity.

Cons

Due to the fact, that entity is stored in few tables, we have to use joins to read the whole object. In our example, while querying the Car entity, the query would look like:

SELECT p.ID, p.NAME, c.BRAND, c.MODEL 
FROM PRODUCT p 
    LEFT JOIN CAR c 
        ON p.ID = c.ID
WHERE p.TYPE = 'Car';

The amount of joins in query grows proportionally to the amount of classes in the hierarchy of the entity. This can have a negative impact on the performance of reading entities.

Summary

The Joined strategy should be chosen, when data integrity is more important than performance, when there is a strong need to control data at the database level.

But when you expect to have many polymorphic queries, this strategy isn’t a good choice.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Joined Table is one of three strategies in JPA dealing with persisting Java domain model into relational database. The main point of this strategy is that each class of the hierarchy have its own table. Let’s check how to use this strategy and what are the consequences of using this solution.

Model

Here are Java classes with JPA mappings:

@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name="type") 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    //Getters and setters
} 
@Entity
@DiscriminatorValue("Car") 
public class Car extends Product {
    private int brand;
    private int model; 
} 
@Entity
public class Toy extends Product {
    private int minimalAge;
}  

We must explicitly define the strategy in @Inheritance annotation at the root entity, because the default is Single Table strategy (described here). Subclasses don’t need any specific configuration – if we don’t want to use default discriminator values, we can customize them using @DiscriminatorValue annotation.

The behavior of this strategy is very intuitive – each class of the hierarchy gives its own table. Each table contains only the primary key of the entity and fields of this corresponding class. To instantiate a particular entity, we have to query all the tables that exist in the hierarchy of this entity. Only the root table contains additional column with discriminator value – based on this information we know which tables we must to query.

Pros

From the point of view of the database, the Joined inheritance strategy is is the most consistent of all three strategies – there are no redundancy in data persistence. We can define not null checks and other constraints on all the columns to control data integrity at the database level.

The fact that we don’t have nullable columns while persisting entity (like in Single Table strategy ) has the positive impact on the amount of memory used by the database – the database use the minimum amount of memory needed to store entity.

Cons

Due to the fact, that entity is stored in few tables, we have to use joins to read the whole object. In our example, while querying the Car entity, the query would look like:

SELECT p.ID, p.NAME, c.BRAND, c.MODEL 
FROM PRODUCT p 
    LEFT JOIN CAR c 
        ON p.ID = c.ID
WHERE p.TYPE = 'Car';

The amount of joins in query grows proportionally to the amount of classes in the hierarchy of the entity. This can have a negative impact on the performance of reading entities.

Summary

The Joined strategy should be chosen, when data integrity is more important than performance, when there is a strong need to control data at the database level.

But when you expect to have many polymorphic queries, this strategy isn’t a good choice.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

When we have to map Java domain model based on the inheritance into relational structure persisted in database, JPA and Hibernate helps us do it in several ways. The default (when you don’t specify it exactly) and the simplest one is the SINGLE_TABLE strategy. Let’s look how we can use it, what pros and cons it gives us.

Model

Here are Java classes with JPA mappings:

 
@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="type") 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String name;
 
    //Getters and setters
} 
 
@Entity
public class Car extends Product {
private int brand;
private int model;
}
 
@Entity
public class Toy extends Product {
private int minimalAge;
}

As you can see, the strategy is configured in the root class of entities hierarchy, by the @Inheritance annotation. If you omit the type of the strategy, the default SINGLE_TABLE will be chosen.

@DiscriminatorColumn specifies the name of the column that is used to distinguish entity types. The annotation is optional, when not specified, the default value “DTYPE” will be used.

All the entities under the root entity don’t need any specific configuration. The only thing we can configure is the value used in the discriminator column for the entity. In this case we do this using @DiscriminatorValue annotation as follows:

@Entity
@DiscriminatorValue("Toy")
public class Toy extends Product {
    private int minimalAge;
} 

In this example “Toy” value will be inserted in the column “type”, when Toy will be persisted. Without specyfying own discriminator value,

Pros

Persisting all entities in one table gives us a good performance, when using polymorphic queries (for both writes and reads). Executing queries that operate on different levels of entities hierarchy, the query runs only on one table, without any joins. Of course, there is also better to control the table, instead if we had many tables – all defined constraints are kept in one place.

Besides, using Single Table strategy, we can use only one Primary Key generation strategy – common for all subclasses – definition of the primary key should be defined only at the root entity level.

Cons

Due to the fact we one table to store all entities, we have to allow to store null values for all fields of subclasses – we can only have not null constraints for fields in the root entity. By using Single Table strategy most of the constraints according data (all checks like ) have to be moved from the database to the application level.

When we have to persist very complicated hierarchy in one table (with most fields in subclasses), the amount of columns with null values can significantly rise. The readability of such rows can be weak.

Summary

Single Table strategy provides the best performance for writes and reads, because queries run only on one table. If we have to disable most of data integrity checks at the database level and move them to our application, the strategy can be very efficient solution.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Suppose we have a list that is backed by an array. In another words – that we have a wrapper around the array. Our question is: how to add or remove elements from that list?

The answer is: We can’t (see array-backed-list for details). But we can create a new List based on the previous one, for example:

List modifiableList = new ArrayList(Arrays.asList(list));

The above code will create modifiable list with any fixed-length constraints. From now you can add or remove elements to modifiableList.
Please be aware that after running this code, you will also loose relation to the backing array – any changes made to modifiableList won’t be reflected in the array – that’s because constructor of the list makes a copy of all references in source list.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

In this tutorial you will find out how to show real SQL statements (with real parameter values instead of question marks), that are send to database. This will greatly help us to better debug our code.

Hibernate configuration allows us to show SQL statements in logs by setting the parameter:

hibernate.show_sql=true

But then generated sql in the logs looks like:

insert into User (id, username, version) values (default, ?, ?)

If the query has the parameters, there will be question marks instead of the real parameters. To get info about the parameters you should use slf4j:

Add maven dependency:

<!-- slf4j-log4j -->
 <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.6.1</version>
</dependency>

Then create log4j.properties file in your classpath with the following content:

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

# Root logger option
log4j.rootLogger=INFO, stdout

# logs the SQL statements
log4j.logger.org.hibernate.SQL=debug 

# Log all JDBC parameters
log4j.logger.org.hibernate.type=trace

The log4j.logger.org.hibernate.SQL parameter hibernate to log SQL statements. The parameter is equivalent to the hibernate.show_sql.
log4j.logger.org.hibernate.type is responsible for logging JDBC parameters.

Now the log should look like this:

10:58:49,627 DEBUG SQL:109 - insert into User (id, username, version) values (default, ?, ?)

10:58:49,635 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [username_688]

10:58:49,637 TRACE BasicBinder:81 - binding parameter [2] as [BIGINT] - [0]

The source code can be downloaded from here.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

In this tutorial you will know, how you can organize efficiently your dependencies in project with multiple modules.

When you have big project with many modules sharing some dependencies its worth having one place, where you can define and organize them.
This approach is called BOM (which stands for Bill Of Materials): It is a place (usually the root module) where you define specific versions of all the dependencies used in the project. Later (in other modules of the project) you can refer to those dependencies without indicating the specific version.
This way of managing versions of dependent libraries introduces consistency into your project.

Some build automation tools have built in dependency management mechanism providing BOM – for example for Maven you can make use of the dependencyManagement configuration.
Unfortunately Gradle doesn’t have such built in functionality, but you can use plugin io.spring.dependency-management to easily achieve the same effect.

Here is shown what the root configuration file should look like:

plugins {
    id "base"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
}

description = """pets"""

allprojects {
    group = 'com.devcases'
    version = '0.0.1-SNAPSHOT'

    apply plugin: 'java'

    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }

    repositories {
        maven { url "http://repo.maven.apache.org/maven2" }
        mavenCentral()
    }
}

subprojects {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    apply plugin: 'io.spring.dependency-management'

    dependencyManagement {
        dependencies {
            dependency 'org.springframework.boot:spring-boot-starter-web:2.1.0.RELEASE'
        }
    }
}

After importing plugin io.spring.dependency-management we can use two sections in the root module:

  • allprojects – for defining common configuration for sub projects and root project
  • subprojects – for defining common configuration for sub projects without the root project
In our example we define repositories which we are using in all modules of our project and a dependency of the spring-boot-starter-web library.
Plugin dependency-management allows us to share any other configuration, not only dependencies – in our example we define sourceCompatibility,  targetCompatibility and import plugin: ‘io.spring.dependency-management’ in all the submodules.
After defining this configuration we can use it in submodules with very small amount of code:
dependencies {
    compile project(':pets-domain')
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
}

The first line of above code snippet imports another module ‘pets-domain’. The second line imports external library.
In submodules we shouldn’t use any versions of the libraries – they are managed only in the root module.

The example code you can download from here
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Assume we have an unordered list of objects and we want to find particular element based on the predicate. As elements can appear in any order, we cannot use any search algorithms, we have to iterate over all the elements in the collection. Let’s check what are the ways of finding such element.

Assume we have a class:

public class Customer {

private String name;

public Customer(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

and the collection:

List<Customer> customers = Arrays.asList(
new Customer("John"),
new Customer("Ted"),
new Customer("Ann"),
new Customer("Joey"));

We will start from Java 6 (because these ways are still actual) and then move to newer versions.

Iterator
public Customer findByName(List<Customer> customers, String name) {
    Iterator<Customer> iterator = customers.iterator();
    while (iterator.hasNext()) {
        Customer customer = iterator.next();
        if (customer.getName().equals(name)) {
            return customer;
        }
    }
    return null;
}

Thanks to the iterator we don’t have to implement the logic of traversing through the collection. We can just check the element the iterator delivers us. In this example we can see there is some boilerplate code according to the use of iterator.

For loop
Customer findByName(List<Customer> customers, String name) {
    for (Customer customer: customers) {
        if (customer.getName().equals(name)) {
            return customer;
        }
    }
return null; }

Iterating using the for loop we can omit the code of using the iterator, it looks much clearer,  but we must remember, that this construction still uses the iterator in the background.

Java 8 Stream
Customer findByName(List<Customer> customers, String name) {
    return customers.stream()
        .filter(customer -> customer.getName().equals(name))
        .findAny()
        .orElse(null);
}

Java 8 introduced new Stream API, which helps us define operations in more declarative way. We only have to implement the predicate (passed to the ‘filter’ method) and the expected result (found element or null). We don’t have to care for implementation details (how the list will be traversed, etc.).

Third-party libraries Google guava

Guava provides similar functionality to Streams – we can use it in older project, in which we can’t migrate to newer version of Java. 

Customer findByName(List<Customer> customers, String name) {
return Iterables.find(customers, new Predicate<Customer>() {
public boolean apply(Customer customer) {
return customer.getName().equals(name) ;
}
});
}
Apache commons

Another great library, which helps us get a result by using predicate:

Customer findByName(List<Customer> customers, String name) {
return IterableUtils.find(customers, new Predicate<Customer>() {
public boolean evaluate(Customer customer) {
return customer.getName().equals(name);
}
});
}


Dashboard

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

In this tutorial we will create simple Spring application based on the Hexagonal Architecture (also called as ports and adapters). This concept is focused on separating implementation of business rules from technical details, it is very flexible and doesn’t require specific implementation (like naming of the modules , classes, adapters and so on). You can use this example as template to start with your own application.

Technologies used:

  1. Spring Boot 2.1.0.RELEASE
  2. JDK 1.8
  3. Gradle 4.10.2
1. Project setup
We will organize our project into several modules:
  • pets-domain – contains business logic (domain data structures and business processing rules). This module should define and provide primary ports – used for calling business logic (like entry point for this module). All secondary ports, which domain should depend on, must also be defined here, but without the implementation. These ports are used to communicate with the world. Interface of all the ports should depend only on domain model.build.gradle for the module:
    dependencies {
      compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
    }
    
  • pets-infrastructure – contains implementation for secondary ports defined in pets-domain module. Implementations of these ports are called secondary adapters – they directly communicate with specific datasources (databases, filesystems, etc), they can also call other applications (REST, SOAP, JMS, etc). In simple words, this module should contain implementation details related with providing data (or with communicating with the world) for the the domain module.build.gradle for the module:
    dependencies {
      compile project(':pets-domain')
    }
  • pets-api – module containing primary adapters (which implement primary ports) – these module translates calls from other systems (other applications or just GUI) to call logic from our domain module.build.gradle for the module:
    dependencies {
      compile project(':pets-domain')
      compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
    
    }
  • pets-app – technical module. It wires all the previous modules and contains configuration for the application
    build.gradle for the module:
    apply plugin: 'application'
    mainClassName = 'com.devcases.pets.PetsApplication'
    dependencies {
      compile project(':pets-api')
      compile project(':pets-infrastructure')
      compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
    }
And here is the root gradle configuration file, gathering ale the dependencies:
plugins {
    id "base"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
}

description = """pets"""

allprojects {
    group = 'com.devcases'
    version = '0.0.1-SNAPSHOT'

    apply plugin: 'java'

    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }

    repositories {
        maven { url "http://repo.maven.apache.org/maven2" }
        mavenCentral()
    }
}

subprojects {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    apply plugin: 'io.spring.dependency-management'

    dependencyManagement {
        dependencies {
            dependency 'org.springframework.boot:spring-boot-starter-web:2.1.0.RELEASE'
        }
    }
}
2. Domain Logic

The most interesting module in this concept is the domain module – as mentioned above, it contains only raw business logic, it doesn’t even know about how it is deployed (any spring annotations, etc).

In our example we have one simple model:

package com.devcases.pets;

public class Pet {
    private String id;
    private String name;
    private String species;

    public Pet(String id, String name, String species) {
        this.id = id;
        this.name = name;
        this.species = species;
    }

    public void play() {
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getSpecies() {
        return species;
    }
}
Notice this model is immutable – it’s important, because it will be returned to other modules.
Here is primary port that should be called for obtaining our list of pets:
package com.devcases.pets;

import java.util.List;

public interface PetService {
  List getAllPets();
}
And implementation of this interface:
package com.devcases.pets;

import java.util.List;

public class PetServiceImpl implements PetService {

  private PetRepository repository;

  public PetServiceImpl(PetRepository repository) {
    this.repository = repository;
  }

  @Override
  public List<Pet> getAllPets() {
    //do some logic to retrieve all pets
    return repository.getAllPets();
  }
}
This class contains some business logic (very simple in our example). We also operate only on objects defined in domain module – we shouldn’t even know how are represented rest requests to our functionality or where the pets are persisted.
Its worth to notice, that there is no technical information about how it will be instantiated – as singleton, prototype, maybe pool of beans? – in this place we don’t bother about these technical things, we are only interested in business rules.
This approach also helps us to build better unit tests – without bothering about dependencies in the spring application contexts, thanks to instantiation by the constructor we also don’t need to use additional frameworks (like mockito) for mocking our dependencies – our tests will be faster.

We see, that the service use the interface PetRepository  to obtain pets – in our case this is the secondary port:

package com.devcases.pets;

import java.util.List;

public interface PetRepository {
  List getAllPets();
}
3. Infrastructure
This modules is dependent on pets-domain module, it contains implementation of secondary port:
package com.devcases.pets;

import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Component
public class PetRepositoryImpl implements PetRepository {

  @Override
  public List getAllPets() {
    //todo replace source of pets with any real datasource
    return new ArrayList<>(Arrays.asList(
        new Pet("1", "Daisy", "dog"),
        new Pet("2", "Bella", "cat")));
  }
}
For simplicity we create list of pets on the fly, but in real application they should be obtained form the real datasource – database (Oracle, PostgreSQL, etc), file, calling other service (for example REST or SOAP) or other. This is also the place where we should map model from other systems to the domain model.
4. Api module
This is module, which should contain technical information about calling our domain. In our case we have spring controller providing rest resource returning our pets:
package com.devcases.pets;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/pets")
public class PetController {

  @Autowired
  private PetService petService;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public List getAllPets() {
    return petService.getAllPets();
  }
}
In this place we could map our domain model to specific response but form simplicity we skip this step.
5. App module

This is the place where all the modules are configured together:

package com.devcases.pets;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PetsApplication {

 public static void main(String[] args) {
  SpringApplication.run(PetsApplication.class, args);
 }
}
package com.devcases.pets.configuration;

import com.devcases.pets.PetRepository;
import com.devcases.pets.PetServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ApplicationConfiguration {

  @Bean
  public PetServiceImpl getUserService(PetRepository petRepository) {
    return new PetServiceImpl(petRepository);
  }
}
Here we decide how service from the domain module is deployed.After compiling, running the application, we can hit the url http://localhost:8080/pets/ and the result should be like that:
[
  {
    "id": "1",
    "name": "Daisy",
    "species": "dog"
  },
  {
    "id": "2",
    "name": "Bella",
    "species": "cat"
  }
]

The example code you can download from here.

Read for later

Articles marked as Favorite are saved for later viewing.
close
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview