我正在使用JPA。如果字符串长度超过列大小,我需要在保存之前修剪字符串。我有以下代码。
可以根据相应字段的setter中的JPA注释截断字符串:
public void setX(String x) {
try {
int size = getClass().getDeclaredField("x").getAnnotation(Column.class).length();
int inLength = x.length();
if (inLength>size)
{
x = x.substring(0, size);
}
} catch (NoSuchFieldException ex) {
} catch (SecurityException ex) {
}
this.x = x;
}
注释本身应如下所示:
@Column(name = "x", length=100)
private String x;
现在我的问题是,我想要许多实体中许多字段的逻辑。如何编写/使上面的逻辑成为通用的,以避免所有字段的所有实体中出现重复的代码。
答案 0 :(得分:0)
我看到两个选项,这两个选项都不会像你想的那样动手。
我尝试了第一条路径并开始变得过于复杂,所以我尝试了#2并使用了this question中的内容。
public static String truncate(String string)
{
try
{
final StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
final Class<?> clazz = Class.forName(stackTraceElement.getClassName());
final BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
final String methodName = stackTraceElement.getMethodName();
final PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
for(final PropertyDescriptor descriptor : props)
{
if(descriptor.getWriteMethod() != null)
{
if(methodName.equals(descriptor.getWriteMethod().getName()))
{
System.out.println(descriptor.getDisplayName());
final Column annotation =
clazz.getDeclaredField(descriptor.getDisplayName()).getAnnotation(Column.class);
if(annotation != null)
{
final int size = annotation.length();
if(size == 255)
{
// Highly likely we hit the default value, which means nothing was specified so just
// move along
}
else if(string.length() > size)
{
string = string.substring(0, size);
}
}
break;
}
}
}
}
catch(final IntrospectionException e)
{
}
catch(final Exception e)
{
}
return string;
}
您有基本的列定义
@Column(name = "personTitle", length = 5)
private String personTitle;
然后在setter中
public void setPersonTitle(final String personTitle)
{
this.personTitle = JpaStringTruncator.truncate(personTitle);
}
这假设您的setter正在调用静态方法,因此您只需要回溯StackTrace中的一些元素。
答案 1 :(得分:0)
我使用的方法是简单地在所有实体类中定义保存每个String字段最大大小的int变量,并在设置器中使用这些变量来修剪字符串(如果它们超过了大小限制)。
由于我是使用Netbeans的Entity classes from database
向导动态生成实体类的,所以我需要一种自动化的方式来生成int变量,如下所示:
public static final int ID_NUMBER_SIZE = 16;
public static final int WEB_SITE_NAME_SIZE = 100;
public static final int WEB_URL_SIZE = 50;
因此,我编写了以下python脚本,该脚本解析给定目录中的所有*.java
文件,并使用正则表达式匹配包含@Size
约束的字段定义。只需在命令行py entities_size.py
上调用脚本并刷新IDE中的显示(在Eclipse中为 F5 ),即可在源文件外部对其进行修改时运行该脚本。如果您首先要测试脚本,则可以注释掉最后一行,将更改写入文件。
import os,glob,re
from pathlib import Path
path = 'C:\\users\\pierre\\git\\myProject\\backend\\src\\main\\java\\ca\\qc\\myDomain\\myApp\\entity'
# For each *.java file in the path above
for filename in glob.glob(os.path.join(path, '*.java')):
with open(filename, 'r') as f:
# Read each file
contents = f.read()
# Find all String variables' name and size with a regex
varsAndSizesTuples = re.findall(r'@Size\(max\s*=\s*(\d+)[\s\S]*?(?=@Column\(name\s*=\s*\"(\w*)\")', contents, re.MULTILINE)
newString = "\n"
# Iterate over each variable and size to create the java code for a new int variable
# and accumulate those declarations in the newString variable
for tuple in varsAndSizesTuples:
newString = newString + "\tpublic static final int " + str(tuple[1]) + "_SIZE = " + str(tuple[0]) + ";\n"
print(filename + "\n" + newString + "\n")
# Finds the position of the class declaration with a regex
index = re.compile(r"public class.*{[^}]").search(contents).end()
# Inserts the new variables declaration right after the class declaration
contents = contents[:index] + newString + contents[index:]
# Write the changes to the file
with open(filename, 'w') as f: f.write(contents)
第一个正则表达式@Size\(max\s*=\s*(\d+)[\s\S]*?(?=@Column\(name\s*=\s*\"(\w*)\")
用于提取字段名称及其大小限制(在regex101上进行测试,请参见下文),而第二个正则表达式public class.*{[^}]
用于查找字段名称和大小限制。 public class
声明以在其后插入新变量声明。
完成此操作后,我编写了以下静态方法以返回修剪后的字符串(如果需要)。请注意,为简单起见,该方法不会测试null
或其他无效参数。
public static String trim(String string, int limit) {
return string.substring(0, Math.min(string.length(), limit) - 1);
}
需要在每个设置器上调用该方法,并使用要验证的字符串及其大小限制:
myEntity.setIdNumber(RefTblInit.trim(stringToPossiblyTrim, MyEntity.ID_NUMBER_SIZE));
这样,我确保我的代码不会因为设置器的参数超出其大小限制而中断。