java - 如何将类名、运行方法名和对象字段传递给AspectJ或其他拦截器?

标签 java jpa localization facelets aspectj

我的问题与本地化有关,我有 JPA 实体,其中包含 fieldnameEN、fieldnameFR、fieldnameRU 等字段。我想编写一些 getter 方法,它自动检测当前区域设置并返回适当的字段。我正在使用facelets,这样的getter将帮助我调用getter并将本地化问题委托(delegate)给后端。区域设置已经存储在 session 中并且获取它不是问题。我知道如何手动执行此类方法,例如

getProperty(){
locale = takeFromSession();
if(locale=en) return getPropertyEN();
if(locale=fr) return getPropertyFR();
}

但我想在 AspectJ 或某些拦截器的帮助下保持 DRY 原则。

当前关于实现的想法 - 在每个 getter 调用中 determine running method name ,将对象状态传递给某个拦截器,并在拦截器中执行区域设置检查并返回已传递给拦截器的字段的适当值

有解决此类问题的可行示例吗?

如何将对象状态传递给拦截器?

有没有更好的方法来解决我的问题?

更新

Kriegaex 建议使用 bundle 。实际上,我们使用 bundle 进行标记(标题和标题),但我们还需要本地化存储在数据库中的实体。 bundle 需要使用“哈希标签”作为 .property 文件中的键,但我不想将实体值存储为哈希标签。 bundle 将迫使用户将业务值填写为“哈希标签”,我不喜欢这样)

即使使用英文值作为键或值的一些哈希值,如果实体有 100 个属性,我们也需要进行 100 次查询。是的,我的意思是 100 个数据库查询,因为据我所知, bundle 存储在 RAM 中,这可能不足以存储翻译,这就是为什么在我们的例子中 bundle 应该位于键值数据库中。

关于重新编译 - 很可能我们只有 3 种语言,并且不需要朝这个方向扩展。

如果有人知道我的主题问题的答案,请分享一些小例子)

最佳答案

AspectJ 无意用于修补不良的应用程序设计。我可以轻松地告诉您如何使用反射编写一些廉价的方面代码,以便为当前语言调用正确的 getter,但是

  • 很丑
  • 速度很慢,
  • 每种语言都有一个属性 + getter,并且在方法名称中编码语言 ID 无法扩展。如果您想添加其他语言,则必须向数十或数百个实体添加字段。

也许您应该考虑使用标准方法,例如资源包作为您的属性名称。通过这种方式,您可以更改文本常量,甚至添加新语言,而无需重新编译代码。因为国际化是一个跨领域的问题,所以如果您希望将它们排除在核心代码之外,您仍然可以使用 AspectJ 来通过 ITD(类型间定义)或其他方式声明您的翻译的访问方法。这样你的核心代码就可以完全与语言无关。

<小时/>

更新:

无论如何,如果您非常想要它,这里有一个示例,向您展示可以使用 AOP(即 AspectJ)做什么。用户gknicker提出的解决方案类似,但它只适用于一个类。我的代码在一个方面保持独立,并且可以一次将其应用到许多类。

计划是使用标记注释手动注释包含多语言字段标题的每个实体类。我编了一个名为@Entity。或者,您还可以通过父类(super class)或类或包名称模式来确定目标类,AspectJ 在这方面非常强大。正如我所说,这只是一个例子。

在下一步中,我们将定义一个执行以下操作的方面:

  • 定义接口(interface)LocalizedCaption
  • 使用反射魔法定义一些示例默认方法,以便
    • 获取一个字段的本地化标题,
    • 获取所有已定义实体字段的所有本地化标题,
    • 获取实体实例的本地化标题和字段值的映射。
  • 使用 ITD(类型间声明)以使所有 @Entity 类实现该接口(interface),从而继承其方法。

最后但并非最不重要的一点是,我们将在示例应用程序中使用新方法。

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Entity {}
package de.scrum_master.app;

@Entity
public class Person {
    public static final String firstNameEN = "first name";
    public static final String firstNameFR = "prénom";
    public static final String firstNameRU = "и́мя";

    public static final String lastNameEN = "last name";
    public static final String lastNameFR = "nom de famille";
    public static final String lastNameRU = "фами́лия";

    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}
package de.scrum_master.aspect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import de.scrum_master.app.Application;
import de.scrum_master.app.Entity;

public aspect EntityCaptionLocaliser {
    public interface LocalisedCaption {
        String getCaption(String attributeName);
    }

    declare parents :
        @Entity * implements LocalisedCaption;

    public String LocalisedCaption.getCaption(String attributeName)
        throws ReflectiveOperationException
    {
        String fieldName = attributeName + Application.locale;
        Field field = getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return (String) field.get(this);
    }

    public Map<String, String> LocalisedCaption.getAllCaptions()
            throws ReflectiveOperationException
        {
            Map<String, String> captions = new HashMap<>();
            for (Field field : getClass().getDeclaredFields()) {
                if (Modifier.isStatic(field.getModifiers()))
                    continue;
                String attributeName = field.getName();
                captions.put(attributeName, getCaption(attributeName));
            }
            return captions;
        }

    public Map<String, Object> LocalisedCaption.getCaptionValuePairs()
            throws ReflectiveOperationException
        {
            Map<String, Object> captions = new HashMap<>();
            for (Field field : getClass().getDeclaredFields()) {
                if (Modifier.isStatic(field.getModifiers()))
                    continue;
                field.setAccessible(true);
                String attributeName = field.getName();
                captions.put(getCaption(attributeName), field.get(this));
            }
            return captions;
        }
}
package de.scrum_master.app;

public class Application {
    public static String locale = "EN";

    public static void main(String[] args) throws Exception {
        Person albert = new Person("Albert", "Einstein");
        System.out.println("Showing localised captions for " + albert + ":");
        locale = "EN";
        System.out.println(albert.getAllCaptions());
        System.out.println(albert.getCaptionValuePairs());
        locale = "FR";
        System.out.println(albert.getAllCaptions());
        System.out.println(albert.getCaptionValuePairs());
        locale = "RU";
        System.out.println(albert.getAllCaptions());
        System.out.println(albert.getCaptionValuePairs());
    }
}

Application.main 的控制台输出:

Showing localised captions for Person [firstName=Albert, lastName=Einstein]:
{lastName=last name, firstName=first name}
{first name=Albert, last name=Einstein}
{lastName=nom de famille, firstName=prénom}
{nom de famille=Einstein, prénom=Albert}
{lastName=фами́лия, firstName=и́мя}
{фами́лия=Einstein, и́мя=Albert}

关于java - 如何将类名、运行方法名和对象字段传递给AspectJ或其他拦截器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27400396/

相关文章:

java - Netbeans 内置 .jar 不适用于内部类文件

java - Netbeans: "Run -> Test Project"不执行任何操作

java - 使用 AuthenticatingSMTPClient 和 SSL?

java - JPA native 查询插入返回 id

java - JPAContainer 和 JPA 版本

swift - 在 Swift 中使用放置器本地化字符串

java - 无法从队列创建热流

ios - 不明白如何本地化iOS react native 应用程序的plist

在 MVC 的 Global.asax 文件中使用 Application_PreRequestHandlerExecute 方法时,Jquery 和 css 在服务器上不起作用

java - 如何在 IntelliJ 社区版中使用 Hibernate?