From 75f5dac16b57e6b19d712df128fd6b98632e561b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 14 Jul 2023 12:16:37 +0200 Subject: [PATCH] Polishing --- .../ROOT/pages/data-access/orm/jpa.adoc | 34 +++++++++---------- .../support/GenericConversionService.java | 5 ++- .../DefaultConversionServiceTests.java | 2 +- .../CollectionToCollectionConverterTests.java | 4 +-- .../GenericConversionServiceTests.java | 2 +- .../jdbc/core/JdbcTemplate.java | 18 +++------- 6 files changed, 28 insertions(+), 37 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc b/framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc index 9dbf42a56d..27d2feca59 100644 --- a/framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc +++ b/framework-docs/modules/ROOT/pages/data-access/orm/jpa.adoc @@ -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, diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index e00b3d44b5..d2b893ab46 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -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) { diff --git a/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java index 3bcc97276f..1709a9a203 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java @@ -659,7 +659,7 @@ class DefaultConversionServiceTests { foo.add("2"); foo.add("3"); @SuppressWarnings("unchecked") - List bar = (List) conversionService.convert(foo, TypeDescriptor.forObject(foo), + List bar = (List) conversionService.convert(foo, new TypeDescriptor(getClass().getField("genericList"))); assertThat(bar).containsExactly(1, 2, 3); } diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java index 5300d01079..2b94fde517 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java @@ -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 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)); } diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java index 596e068b15..99b6ae3f6f 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java @@ -302,7 +302,7 @@ class GenericConversionServiceTests { void wildcardMap() throws Exception { Map 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); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java index dfc37eb2e4..4ca00bd4b3 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -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, 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, 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, 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, SqlProvider { @Nullable @@ -1373,7 +1365,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } } } - if (!(param.isResultsParameter())) { + if (!param.isResultsParameter()) { sqlColIndex++; } }