Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Source: https://spring.io/projects/spring-data-jpa

By default Spring uses Hibernate as the default JPA vendor. Although Hibernate is a good choice, some of us someone may prefer prefers to use EclipseLink as it was supposed to be the reference implementation for the Java Persistence JSR.
How configuring Spring-Boot to use EclipseLink as the JPA provider: https://blog.marcnuri.com/spring-data-jpa-eclipselink-configuring-spring-boot-to-use-eclipselink-as-the-jpa-provider/

...

The Spring Framework provides a consistent abstraction for transaction management. The Spring Framework’s declarative transaction management is made possible with Spring aspect-oriented programming (AOP), although, as the transactional aspects code comes with the Spring Framework distribution and may be used in a boilerplate fashion, AOP concepts do not generally have to be understood to make effective use of this code.

Source: https://docs.spring.io/spring-framework/docs/45.23.x7/spring-framework-reference/html/transactiondata-access.htmlhtml#transaction

Aspect-Oriented Programming

Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns such as transaction management that cut across multiple types and objects. (Such concerns are often termed crosscutting concerns in AOP literature.)
One of the key components of Spring is the AOP framework. While the Spring IoC (Inversion of control) container does not depend on AOP, meaning you do not need to use AOP if you don’t want to, AOP complements Spring IoC to provide a very capable middleware solution.

Source: https://docs.spring.io/spring-framework/docs/45.3.15.RELEASE/spring-framework-7/reference/html/aopcore.htmlhtml#aop

Use a Higher-level Database Migration Tool

...

Code Block
languagejava
titleJpaToscaProperty
linenumberstrue
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;


@Entity
@Table(name = "ToscaProperty")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Data
@EqualsAndHashCode(callSuper = false)
public class JpaToscaProperty extends PfConcept implements PfAuthorative<ToscaProperty> {
    private static final long serialVersionUID = 1675770231921107988L;

    @EmbeddedId
    @VerifyKey
    @NotNull
    private PfReferenceKey key;

    @Column
    @VerifyKey
    @NotNull
    private PfConceptKey type;

    @Column
    @NotBlank
    private String description;

Spring Repository

Using With Spring Data JPA it needs , is a good choice to implement a repository for each model.

Code Block
languagejava
titleJpaToscaPropertyRepository
linenumberstrue
@Repository
public interface JpaToscaPropertyRepository extends JpaRepository<JpaToscaProperty, PfReferenceKey> {

}

repositories.
The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.

Source: https://docs.spring.io/spring-data/data-commons/docs/2.5.1/reference/html/#repositoriesand also it needs to implement a JUnit test

Code Block
languagejava
titleJpaToscaPropertyRepositoryTestJpaToscaPropertyRepository
linenumberstrue
@Repository
public interface JpaToscaPropertyRepository extends JpaRepository<JpaToscaProperty, PfReferenceKey> {

}

and also it needs to implement a JUnit test

Code Block
languagejava
titleJpaToscaPropertyRepositoryTest
linenumberstrue
@ExtendWith(SpringExtension.class)
@DataJpaTest
@Import(value @ExtendWith(SpringExtension.class)
@DataJpaTest
@Import(value = ParticipantPolicyParameters.class)
@TestPropertySource(locations = {"classpath:application_test.properties"})
class JpaToscaPropertyRepositoryTest {

    @Autowired
    private JpaToscaPropertyRepository toscaPropertyRepository;

    @Test
    void test() {
        JpaToscaProperty toscaProperty = new JpaToscaProperty();
        PfReferenceKey key = toscaProperty.getKey();

        Map<String, String> metadata = new HashMap<>();
        metadata.put("Key", "Value");
        metadata.put("K", "V");

        List<JpaToscaConstraint> constraints = new ArrayList<>();
        String[] list = new String[] {"First", "Second"};
        constraints.add(new JpaToscaConstraintValidValues(Stream.of(list).collect(Collectors.toList())));

        toscaProperty.setDefaultValue("DefaultValue");
        toscaProperty.setDescription("Description");
        toscaProperty.setRequired(true);
        toscaProperty.setStatus(ToscaProperty.Status.EXPERIMENTAL);
        toscaProperty.setMetadata(metadata);
        toscaProperty.setConstraints(constraints);
        toscaPropertyRepository.save(toscaProperty);

        Optional<JpaToscaProperty> opt = toscaPropertyRepository.findById(key);
        assertThat(opt).isNotEmpty();
        JpaToscaProperty actual = opt.get();
        assertThat(actual.getDefaultValue()).isEqualTo(toscaProperty.getDefaultValue());
        assertThat(actual.getDescription()).isEqualTo(toscaProperty.getDescription());
        assertThat(actual.isRequired()).isEqualTo(toscaProperty.isRequired());
        assertThat(actual.getStatus()).isEqualTo(toscaProperty.getStatus());
        assertThat(actual.getType()).isEqualTo(toscaProperty.getType());
        assertThat(actual.getConstraints()).isEqualTo(toscaProperty.getConstraints());
    }
}

Spring 

Using Dao

Dao objects are already implemented in Policy Framework, and there is a way to use them and avoid to create repositories, but It needs to create a new DefaultPfDao class that uses the Entity Manger with no "begin transaction" and no "commit".Example how to convert ControlLoopInstantiationProvider class in Spring style using "@Services" and "@Transactional"

Code Block
languagejava
titleControlLoopInstantiationProviderDefaultPfDao
linenumberstrue
@Service
public class ControlLoopInstantiationProviderDefaultPfDao {
 implements PfDao {
    private static final ControlLoopProvider controlLoopProvider;Logger LOGGER = LoggerFactory.getLogger(DefaultPfDao.class);

    private final CommissioningProviderEntityManager commissioningProviderentityManager;

    /**
     * Create a instantiation providerConstructor.
     *
     * @param databaseProviderParameters the parameters for database accessentityManager EntityManager
     */
    public ControlLoopInstantiationProvider(ControlLoopProvider controlLoopProvider,DefaultPfDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    CommissioningProvider commissioningProvider) {}

    @Override
    public void init(final DaoParameters daoParameters) this.controlLoopProviderthrows =PfModelException controlLoopProvider;{
        this.commissioningProvider = commissioningProvider;// Not need
    }

    @Transactional@Override
    public InstantiationResponse<T createControlLoops(ControlLoops controlLoops) throws PfModelExceptionextends PfConcept> void create(final T obj) {
        forif (ControlLoopobj controlLoop : controlLoops.getControlLoopList()== null) {
            ControlLoop checkControlLoop = controlLoopProvider.getControlLoop(controlLoop.getKey().asIdentifier())return;
        }
    if (checkControlLoop != null) { entityManager.merge(obj);
    }

    @Override
    public <T extends PfConcept> throwvoid new PfModelException(Response.Status.BAD_REQUEST,
   delete(final T obj) {
        entityManager.remove(entityManager.contains(obj) ? obj : entityManager.merge(obj));
    }


EntityManager is not thread safe, and it need to use @PersistenceContext annotation, so Spring will inject a thread-safe proxy for the actual transactional EntityManager.

Code Block
languagejava
titlePolicyModelsProviderImpl
linenumberstrue
@Service
@Transactional
public class PolicyModelsProviderImpl implements  controlLoop.getKey().asIdentifier() + " already defined");PolicyModelsProvider {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
  }
  public ToscaServiceTemplate createServiceTemplate(@NonNull ToscaServiceTemplate serviceTemplate)  }{
        BeanValidationResult validationResult = validateControlLoops(controlLoops)LOGGER.debug("->createServiceTemplate: serviceTemplate={}", serviceTemplate);
        if (!validationResult.isValid()) try {

            throwToscaServiceTemplate new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());createdServiceTemplate =
        }
        controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());

        InstantiationResponse response = new InstantiationResponse();
new SimpleToscaProvider().appendToServiceTemplate(new DefaultPfDao(entityManager),
          response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
                 .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList())) new JpaToscaServiceTemplate(serviceTemplate)).toAuthorative();

        return response    LOGGER.debug("<-createServiceTemplate: createdServiceTemplate={}", createdServiceTemplate);
            return createdServiceTemplate;
        } catch (Exception pfme) {

...

            throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, pfme.getMessage(), pfme);
        }
    }

Spring Service

Example how to convert ControlLoopInstantiationProvider class in Spring style using "@Service" and "@Transactional"

Code Block
languagejava
titleControlLoopInstantiationProvider
linenumberstrue
@Service
public class ControlLoopInstantiationProvider {
    private final ControlLoopProvider controlLoopProvider;
    private final CommissioningProvider commissioningProvider;

    /**
     * Create a instantiation provider.
     *
     * @param databaseProviderParameters the parameters for database access
     */
    public ControlLoopInstantiationProvider(ControlLoopProvider controlLoopProvider,
            CommissioningProvider commissioningProvider) {
        this.controlLoopProvider = controlLoopProvider;
        this.commissioningProvider = commissioningProvider;
    }

    @Transactional
    public InstantiationResponse createControlLoops(ControlLoops controlLoops) throws PfModelException {
        for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
            ControlLoop checkControlLoop = controlLoopProvider.getControlLoop(controlLoop.getKey().asIdentifier());
            if (checkControlLoop != null) {
                throw new PfModelException(Response.Status.BAD_REQUEST,
                        controlLoop.getKey().asIdentifier() + " already defined");
            }
        }
        BeanValidationResult validationResult = validateControlLoops(controlLoops);
        if (!validationResult.isValid()) {
            throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
        }
        controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());

        InstantiationResponse response = new InstantiationResponse();
        response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
                .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));

        return response;
    }

Transaction

Transaction Propagation in SpringBoot:

  • REQUIRED is the default propagation. Spring checks if there is an active transaction, then it creates a new one if nothing existed;
  • For SUPPORTS, Spring first checks if an active transaction exists. If a transaction exists, then the existing transaction will be used. If there isn't a transaction, it is executed non-transactional;
  • When the propagation is MANDATORY, if there is an active transaction, then it will be used. If there isn't an active transaction, then Spring throws an exception;
  • For transactional logic with NEVER propagation, Spring throws an exception if there's an active transaction;
  • NOT_SUPPORTED, Spring at first suspends the current transaction if it exists, then the business logic is executed without a transaction;
  • When the propagation is REQUIRES_NEW, Spring suspends the current transaction if it exists and then creates a new one.

Read only Transaction 

If the transaction is effectively read-only, it allows for corresponding optimizations at runtime. (https://stackoverflow.com/questions/1614139/spring-transactional-read-only-propagation)


NoteIn Spring, @Transactional works by creating a proxy of the class and intercepting the annotated method (AOP Proxies). This means that @Transactional doesn't work if you are calling the annotated method from another method of the same class.