Polishing

This commit is contained in:
Juergen Hoeller 2023-07-14 12:16:37 +02:00
parent bddd3feb83
commit 75f5dac16b
6 changed files with 28 additions and 37 deletions

View File

@ -281,8 +281,8 @@ Spring Data JPA, make sure to set up deferred bootstrapping for its repositories
[[orm-jpa-dao]]
== Implementing DAOs Based on JPA: `EntityManagerFactory` and `EntityManager`
NOTE: Although `EntityManagerFactory` instances are thread-safe, `EntityManager` instances are
not. The injected JPA `EntityManager` behaves like an `EntityManager` fetched from an
NOTE: Although `EntityManagerFactory` instances are thread-safe, `EntityManager` instances
are not. The injected JPA `EntityManager` behaves like an `EntityManager` fetched from an
application server's JNDI environment, as defined by the JPA specification. It delegates
all calls to the current transactional `EntityManager`, if any. Otherwise, it falls back
to a newly created `EntityManager` per operation, in effect making its usage thread-safe.
@ -290,8 +290,8 @@ to a newly created `EntityManager` per operation, in effect making its usage thr
It is possible to write code against the plain JPA without any Spring dependencies, by
using an injected `EntityManagerFactory` or `EntityManager`. Spring can understand the
`@PersistenceUnit` and `@PersistenceContext` annotations both at the field and the method level
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain JPA DAO implementation
that uses the `@PersistenceUnit` annotation:
if a `PersistenceAnnotationBeanPostProcessor` is enabled. The following example shows a plain
JPA DAO implementation that uses the `@PersistenceUnit` annotation:
[tabs]
======
@ -384,9 +384,9 @@ Consider the following example:
----
The main problem with such a DAO is that it always creates a new `EntityManager` through
the factory. You can avoid this by requesting a transactional `EntityManager` (also
called a "`shared EntityManager`" because it is a shared, thread-safe proxy for the actual
transactional EntityManager) to be injected instead of the factory. The following example shows how to do so:
the factory. You can avoid this by requesting a transactional `EntityManager` (also called a
"`shared EntityManager`" because it is a shared, thread-safe proxy for the actual transactional
EntityManager) to be injected instead of the factory. The following example shows how to do so:
[tabs]
======
@ -430,19 +430,19 @@ The `@PersistenceContext` annotation has an optional attribute called `type`, wh
`EntityManager` proxy. The alternative, `PersistenceContextType.EXTENDED`, is a completely
different affair. This results in a so-called extended `EntityManager`, which is not
thread-safe and, hence, must not be used in a concurrently accessed component, such as a
Spring-managed singleton bean. Extended `EntityManager` instances are only supposed to be used in
stateful components that, for example, reside in a session, with the lifecycle of the
Spring-managed singleton bean. Extended `EntityManager` instances are only supposed to be used#
in stateful components that, for example, reside in a session, with the lifecycle of the
`EntityManager` not tied to a current transaction but rather being completely up to the
application.
.Method- and field-level Injection
****
You can apply annotations that indicate dependency injections (such as `@PersistenceUnit` and
`@PersistenceContext`) on field or methods inside a class -- hence the
expressions "`method-level injection`" and "`field-level injection`". Field-level
annotations are concise and easier to use while method-level annotations allow for further
processing of the injected dependency. In both cases, the member visibility (public,
protected, or private) does not matter.
`@PersistenceContext`) on field or methods inside a class -- hence the expressions
"`method-level injection`" and "`field-level injection`". Field-level annotations are
concise and easier to use while method-level annotations allow for further processing of the
injected dependency. In both cases, the member visibility (public, protected, or private)
does not matter.
What about class-level annotations?
@ -451,9 +451,9 @@ injection.
****
The injected `EntityManager` is Spring-managed (aware of the ongoing transaction).
Even though the new DAO implementation uses method-level
injection of an `EntityManager` instead of an `EntityManagerFactory`, no change is
required in the application context XML, due to annotation usage.
Even though the new DAO implementation uses method-level injection of an `EntityManager`
instead of an `EntityManagerFactory`, no change is required in the bean definition
due to annotation usage.
The main advantage of this DAO style is that it depends only on the Java Persistence API.
No import of any Spring class is required. Moreover, as the JPA annotations are understood,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -205,8 +205,7 @@ public class GenericConversionService implements ConfigurableConversionService {
* @param targetType the target type
* @return the converted value
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is {@code null},
* or sourceType is {@code null} but source is not {@code null}
* @throws IllegalArgumentException if targetType is {@code null}
*/
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetType) {

View File

@ -659,7 +659,7 @@ class DefaultConversionServiceTests {
foo.add("2");
foo.add("3");
@SuppressWarnings("unchecked")
List<Integer> bar = (List<Integer>) conversionService.convert(foo, TypeDescriptor.forObject(foo),
List<Integer> bar = (List<Integer>) conversionService.convert(foo,
new TypeDescriptor(getClass().getField("genericList")));
assertThat(bar).containsExactly(1, 2, 3);
}

View File

@ -193,7 +193,7 @@ class CollectionToCollectionConverterTests {
@Test
void listToCollectionNoCopyRequired() throws NoSuchFieldException {
List<?> input = new ArrayList<>(Arrays.asList("foo", "bar"));
assertThat(conversionService.convert(input, TypeDescriptor.forObject(input),
assertThat(conversionService.convert(input,
new TypeDescriptor(getClass().getField("wildcardCollection")))).isSameAs(input);
}
@ -253,7 +253,7 @@ class CollectionToCollectionConverterTests {
List<String> list = new ArrayList<>();
list.add("A");
list.add("C");
assertThat(conversionService.convert(list, TypeDescriptor.forObject(list), new TypeDescriptor(getClass().getField("enumSet")))).isEqualTo(EnumSet.of(MyEnum.A, MyEnum.C));
assertThat(conversionService.convert(list, new TypeDescriptor(getClass().getField("enumSet")))).isEqualTo(EnumSet.of(MyEnum.A, MyEnum.C));
}

View File

@ -302,7 +302,7 @@ class GenericConversionServiceTests {
void wildcardMap() throws Exception {
Map<String, String> input = new LinkedHashMap<>();
input.put("key", "value");
Object converted = conversionService.convert(input, TypeDescriptor.forObject(input), new TypeDescriptor(getClass().getField("wildcardMap")));
Object converted = conversionService.convert(input, new TypeDescriptor(getClass().getField("wildcardMap")));
assertThat(converted).isEqualTo(input);
}

View File

@ -417,9 +417,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL statement [" + sql + "]");
}
/**
* Callback to execute the statement.
*/
// Callback to execute the statement.
class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
@Override
@Nullable
@ -445,9 +443,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL query [" + sql + "]");
}
/**
* Callback to execute the query.
*/
// Callback to execute the query.
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
@Override
@Nullable
@ -542,9 +538,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL update [" + sql + "]");
}
/**
* Callback to execute the update statement.
*/
// Callback to execute the update statement.
class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
@Override
public Integer doInStatement(Statement stmt) throws SQLException {
@ -570,9 +564,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
logger.debug("Executing SQL batch update of " + sql.length + " statements");
}
/**
* Callback to execute the batch update.
*/
// Callback to execute the batch update.
class BatchUpdateStatementCallback implements StatementCallback<int[]>, SqlProvider {
@Nullable
@ -1373,7 +1365,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
}
}
}
if (!(param.isResultsParameter())) {
if (!param.isResultsParameter()) {
sqlColIndex++;
}
}