Java 截断要保存的字符串?

Java 截断要保存的字符串?,java,hibernate,jpa,Java,Hibernate,Jpa,我正在使用JPA。如果字符串的长度大于列的大小,我需要在保存之前修剪字符串。我有下面的代码 可以根据setter中相应字段的JPA注释截断字符串: public void setX(String x) { try { int size = getClass().getDeclaredField("x").getAnnotation(Column.class).length(); int inLength = x.length(); if (

我正在使用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;

现在我的问题是,我想要在许多实体的许多字段中使用上述逻辑。我如何编写/使上述逻辑成为通用逻辑,以避免所有字段的所有实体中出现重复代码。

我看到了两个选项,这两个选项都不会像您希望的那样随意

  • 在库org.Reflections中使用方面。我认为这必须是aspectj的编译时,因为您必须使用反射来获取所有具有注释的字段,然后确定哪些setter属于这些字段,然后围绕这些字段应用一个方面
  • 在每个setter中使用内部反射和一行代码的静态方法
  • 我尝试了第一条路径,但它开始变得太复杂,所以我尝试了#2,并使用了在中找到的一些东西

    然后在二传中

    public void setPersonTitle(final String personTitle)
    {
        this.personTitle = JpaStringTruncator.truncate(personTitle);
    }
    

    这假设您的setter正在调用静态方法,因此您只需回溯StackTrace中的几个元素。

    我使用的方法只是在所有实体类中定义保存每个字符串字段最大大小的int变量,并在setter中使用这些变量来修剪超过大小限制的字符串

    由于我使用Netbeans的“从数据库生成实体类”向导动态生成实体类,因此我需要一种自动生成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\u 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*)\”)
    用于提取字段名及其大小限制(测试,请参见下文),而第二个正则表达式
    公共类。*{[^}]
    用于查找
    公共类
    声明,以便在声明之后插入新变量声明

    完成后,我编写了以下静态方法来返回修剪后的字符串(如果需要)

    public static String trim(String string, int limit) {
        return string.substring(0, Math.min(string.length(), limit) - 1);
    }
    
    需要使用要验证的字符串及其大小限制对每个setter调用该方法:

    myEntity.setIdNumber(RefTblInit.trim(stringToPossiblyTrim, MyEntity.ID_NUMBER_SIZE));
    

    通过这种方式,我确保我的代码不会因为setter的参数超出其大小限制而中断。

    您可以创建自己的注释来完成这项工作。@LuiggiMendoza是否有带有活动代码的注释?我是否误解了您的注释?@laune您说带有活动代码的注释是什么意思?不是答案,但这看起来像是一个糟糕的idea对我来说。我最不想从计算机上得到的是告诉我,我的2000个字符的故事已经被成功地接受和保存,尽管它只保存了前100个字符,并悄悄地丢弃了其余的字符。@karthikmanchala如果用户的输入长度是2000,用户应该会收到一条错误消息(或者更好:根本无法发布),因为输入不能存储在数据库中。这是我的全部观点。如果没有用户,并且我正在从文件或其他东西导入描述,那么这种截断应该在业务层处理,而不是在模型中。
    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));