Skip to content

Commit 381f5a4

Browse files
committed
Add detailed unknown column error handling
Introduced `UnknownColumnAdditionalInfoException` to provide enhanced error details, including a mapping table. Updated `UnknownColumnHandler` to support additional context using a column name map and added `ColumnNameMapFormatter` for formatted table creation. Added related tests to ensure accuracy of the new functionality.
1 parent 0ddff9a commit 381f5a4

File tree

10 files changed

+433
-6
lines changed

10 files changed

+433
-6
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright Doma Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.seasar.doma.internal.jdbc.command;
17+
18+
import java.util.Map;
19+
import java.util.TreeMap;
20+
21+
public class ColumnNameMapFormatter {
22+
public static String format(Map<String, MappingSupport.PropType> columnNameMap) {
23+
StringBuilder buf = new StringBuilder();
24+
buf.append("------------------------------------------------------\n");
25+
buf.append("Lowercase Column Name -> Property Name (Entity Name)\n");
26+
buf.append("------------------------------------------------------\n");
27+
TreeMap<String, MappingSupport.PropType> sortedMap = new TreeMap<>(columnNameMap);
28+
for (Map.Entry<String, MappingSupport.PropType> entry : sortedMap.entrySet()) {
29+
String columnName = entry.getKey();
30+
MappingSupport.PropType propType = entry.getValue();
31+
buf.append(columnName);
32+
buf.append(" -> ");
33+
buf.append(propType.name());
34+
buf.append(" (");
35+
buf.append(propType.entityType().getName());
36+
buf.append(")\n");
37+
}
38+
buf.append("------------------------------------------------------");
39+
return buf.toString();
40+
}
41+
}

doma-core/src/main/java/org/seasar/doma/internal/jdbc/command/EntityProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ protected ENTITY build(ResultSet resultSet) throws SQLException {
9595
return entity;
9696
}
9797

98+
@SuppressWarnings("removal")
9899
@Deprecated(forRemoval = true)
99100
protected HashMap<Integer, EntityPropertyType<ENTITY, ?>> createIndexMap(
100101
ResultSetMetaData resultSetMeta, EntityType<ENTITY> entityType) throws SQLException {

doma-core/src/main/java/org/seasar/doma/internal/jdbc/command/MappingSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public Map<Integer, MappingSupport.PropType> createIndexMap(
9898
if (ROWNUMBER_COLUMN_NAME.equals(lowerCaseColumnName)) {
9999
continue;
100100
}
101-
unknownColumnHandler.handle(query, entityType, lowerCaseColumnName);
101+
unknownColumnHandler.handle(query, entityType, lowerCaseColumnName, columnNameMap);
102102
} else {
103103
unmappedPropertySet.remove(propertyType);
104104
indexMap.put(i, propertyType);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright Doma Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.seasar.doma.jdbc;
17+
18+
import java.io.Serial;
19+
import java.util.Objects;
20+
import org.seasar.doma.message.Message;
21+
22+
public class UnknownColumnAdditionalInfoException extends UnknownColumnException {
23+
24+
@Serial private static final long serialVersionUID = 1L;
25+
26+
private final String additionalInfo;
27+
28+
public UnknownColumnAdditionalInfoException(
29+
SqlLogType logType, UnknownColumnException exception, String additionalInfo) {
30+
super(
31+
Message.DOMA2238,
32+
new Object[] {
33+
exception.getColumnName(),
34+
exception.getEntityClassName(),
35+
exception.getSqlFilePath(),
36+
choiceSql(logType, exception.getRawSql(), exception.getFormattedSql()),
37+
additionalInfo
38+
},
39+
exception.getColumnName(),
40+
exception.getExpectedPropertyName(),
41+
exception.getEntityClassName(),
42+
exception.getKind(),
43+
exception.getRawSql(),
44+
exception.getFormattedSql(),
45+
exception.getSqlFilePath());
46+
this.additionalInfo = Objects.requireNonNull(additionalInfo);
47+
}
48+
49+
public String getAdditionalInfo() {
50+
return additionalInfo;
51+
}
52+
}

doma-core/src/main/java/org/seasar/doma/jdbc/UnknownColumnException.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
*/
1616
package org.seasar.doma.jdbc;
1717

18+
import java.io.Serial;
1819
import org.seasar.doma.message.Message;
20+
import org.seasar.doma.message.MessageResource;
1921

2022
/** Thrown to indicate that there is the column that is unknown to an entity. */
2123
public class UnknownColumnException extends JdbcException {
2224

23-
private static final long serialVersionUID = 1L;
25+
@Serial private static final long serialVersionUID = 1L;
2426

2527
protected final String columnName;
2628

@@ -45,13 +47,35 @@ public UnknownColumnException(
4547
String rawSql,
4648
String formattedSql,
4749
String sqlFilePath) {
48-
super(
50+
this(
4951
Message.DOMA2002,
52+
new Object[] {
53+
columnName,
54+
expectedPropertyName,
55+
entityClassName,
56+
sqlFilePath,
57+
choiceSql(logType, rawSql, formattedSql)
58+
},
5059
columnName,
5160
expectedPropertyName,
5261
entityClassName,
53-
sqlFilePath,
54-
choiceSql(logType, rawSql, formattedSql));
62+
kind,
63+
rawSql,
64+
formattedSql,
65+
sqlFilePath);
66+
}
67+
68+
protected UnknownColumnException(
69+
MessageResource messageCode,
70+
Object[] args,
71+
String columnName,
72+
String expectedPropertyName,
73+
String entityClassName,
74+
SqlKind kind,
75+
String rawSql,
76+
String formattedSql,
77+
String sqlFilePath) {
78+
super(messageCode, args);
5579
this.columnName = columnName;
5680
this.expectedPropertyName = expectedPropertyName;
5781
this.entityClassName = entityClassName;

doma-core/src/main/java/org/seasar/doma/jdbc/UnknownColumnHandler.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.seasar.doma.jdbc;
1717

18+
import java.util.Map;
19+
import org.seasar.doma.internal.jdbc.command.ColumnNameMapFormatter;
20+
import org.seasar.doma.internal.jdbc.command.MappingSupport;
1821
import org.seasar.doma.jdbc.entity.EntityType;
1922
import org.seasar.doma.jdbc.entity.NamingType;
2023
import org.seasar.doma.jdbc.query.Query;
@@ -30,6 +33,7 @@ public interface UnknownColumnHandler {
3033
* @param unknownColumnName the name of the unknown column
3134
* @throws UnknownColumnException if this handler does not allow the unknown column
3235
*/
36+
@Deprecated(forRemoval = true)
3337
default void handle(Query query, EntityType<?> entityType, String unknownColumnName) {
3438
Sql<?> sql = query.getSql();
3539
Naming naming = query.getConfig().getNaming();
@@ -44,4 +48,31 @@ default void handle(Query query, EntityType<?> entityType, String unknownColumnN
4448
sql.getFormattedSql(),
4549
sql.getSqlFilePath());
4650
}
51+
52+
/**
53+
* Handles the unknown column with additional context provided by the column name map.
54+
*
55+
* @param query the query associated with the operation
56+
* @param entityType the entity type description
57+
* @param unknownColumnName the name of the unknown column
58+
* @param columnNameMap the map containing column names and their corresponding property types
59+
* @throws UnknownColumnAdditionalInfoException if handling the unknown column fails with
60+
* additional information
61+
*/
62+
default void handle(
63+
Query query,
64+
EntityType<?> entityType,
65+
String unknownColumnName,
66+
Map<String, MappingSupport.PropType> columnNameMap) {
67+
try {
68+
handle(query, entityType, unknownColumnName);
69+
} catch (UnknownColumnException original) {
70+
String additionalInfo = ColumnNameMapFormatter.format(columnNameMap);
71+
UnknownColumnAdditionalInfoException ex =
72+
new UnknownColumnAdditionalInfoException(
73+
query.getConfig().getExceptionSqlLogType(), original, additionalInfo);
74+
ex.addSuppressed(original);
75+
throw ex;
76+
}
77+
}
4778
}

doma-core/src/main/java/org/seasar/doma/message/Message.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ public enum Message implements MessageResource {
277277
DOMA2237(
278278
"Duplicate column name \"{0}\" found in ResultSetMetaData. Column names must be unique."
279279
+ "\nPATH=[{1}].\nSQL=[{2}]"),
280+
DOMA2238(
281+
"""
282+
While the column "{0}" is in the result set, the corresponding property is not found in the entity class "{1}".
283+
Check the following mapping table:
284+
{4}
285+
PATH=[{2}]
286+
SQL=[{3}]"""),
280287

281288
// expression
282289
DOMA3001(
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright Doma Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.seasar.doma.internal.jdbc.command;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
20+
import example.entity._Dept;
21+
import example.entity._Emp;
22+
import java.util.HashMap;
23+
import java.util.Map;
24+
import org.junit.jupiter.api.Test;
25+
26+
class ColumnNameMapFormatterTest {
27+
28+
@Test
29+
void test_format_withPopulatedMap() {
30+
_Emp emp = _Emp.getSingletonInternal();
31+
_Dept dept = _Dept.getSingletonInternal();
32+
33+
Map<String, MappingSupport.PropType> map = new HashMap<>();
34+
map.put(
35+
emp.version.getColumnName().toLowerCase(),
36+
new MappingSupport.PropType(emp, emp.version, ""));
37+
map.put(
38+
dept.name.getColumnName().toLowerCase(), new MappingSupport.PropType(dept, dept.name, ""));
39+
map.put(
40+
emp.salary.getColumnName().toLowerCase(), new MappingSupport.PropType(emp, emp.salary, ""));
41+
42+
String expected =
43+
"""
44+
------------------------------------------------------
45+
Lowercase Column Name -> Property Name (Entity Name)
46+
------------------------------------------------------
47+
name -> name (Dept)
48+
salary -> salary (Emp)
49+
version -> version (Emp)
50+
------------------------------------------------------""";
51+
52+
String actual = ColumnNameMapFormatter.format(map);
53+
54+
assertEquals(expected, actual);
55+
}
56+
}

doma-core/src/test/java/org/seasar/doma/internal/jdbc/command/EntityProviderTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.math.BigDecimal;
2626
import java.sql.SQLException;
2727
import java.util.Collections;
28+
import java.util.Map;
2829
import org.junit.jupiter.api.Test;
2930
import org.seasar.doma.FetchType;
3031
import org.seasar.doma.internal.jdbc.mock.ColumnMetaData;
@@ -249,7 +250,11 @@ public boolean isResultStream() {
249250

250251
protected static class EmptyUnknownColumnHandler implements UnknownColumnHandler {
251252
@Override
252-
public void handle(Query query, EntityType<?> entityType, String unknownColumnName) {}
253+
public void handle(
254+
Query query,
255+
EntityType<?> entityType,
256+
String unknownColumnName,
257+
Map<String, MappingSupport.PropType> columnNameMap) {}
253258
}
254259

255260
protected static class EmptyUnknownColumnHandlerConfig extends MockConfig {

0 commit comments

Comments
 (0)