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

时间:2014-12-10 11:56:12

标签: java jpa localization facelets aspectj

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

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

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

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

有没有解决此类问题的工作示例?

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

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

更新

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

即使使用英语值作为键或某些哈希值,如果实体具有100个属性,我们需要进行100次查询。是的,我的意思是100个DB查询,因为存储在RAM中的AFAIK包可能不足以存储翻译,这就是为什么在我们的案例中捆绑应该在键值DB中。

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

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

2 个答案:

答案 0 :(得分:1)

AspectJ不打算用于修补错误的应用程序设计。我可以很容易地告诉你如何使用反射编写一些廉价的方面代码,以便为当前语言调用正确的getter,但是

  • 很难看,
  • 很慢,
  • 每种语言具有一个属性+ getter,并且在方法名称中编码语言ID不会缩放。如果要添加其他语言,则必须向数十个或数百个实体添加字段。

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


<强>更新

无论如何,如果你想要这么多,这里有一个样本,向你展示你可以用AOP做什么,即使用AspectJ。用户 gknicker 提出的解决方案类似,但它仅适用于一个类。我在一个方面保持代码分离,并可以同时将它应用于许多类。

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

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

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

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

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}

答案 1 :(得分:0)

最好使用标准Java i18n

但是,如果你坚持追求当前的设计,这里有一个使用反射的例子。

public class Scratch
{
    public static void main(String[] args)
    {
        System.out.println(new Scratch().getProperty());
    }

    String propertyEN = "want";
    String propertyFR = "voulez";

    public String getProperty()
    {
        return (String)getForLocale("property");
    }

    private Object getForLocale(String attributeName)
    {
        String fieldName = attributeName + getLocale();
        try {
            Field field = getClass().getDeclaredField(fieldName);
            return field.get(this);
        } catch (ReflectiveOperationException e) {
            return e.getMessage();
        }
    }

    private String getLocale()
    {
        return "EN"; // takeFromSession();
    }
}