【问题标题】:Objectify Translator as JPA Attribute ConverterObjectify Translator 作为 JPA 属性转换器
【发布时间】:2015-11-14 03:35:19
【问题描述】:

我有一个这样的 POJO 结构

@Entity
public class ClassA {

    @Id
    public Long id;

    public ClassB classbObject;
}

还有一个班级

@Entity
public class ClassB {
    @Id
    public Long id;

    public String fieldA;

    public String fieldB;
}

现在,根据自定义条件,我需要将 classbObject 保存为嵌入的(Objectify 的默认行为)或仅 id 属性(这里是 Translator)。

此条件也适用于单个字段ClassA 或多个字段List<ClassA>

如果对象只保存为 ID,我还需要对其进行索引以对其进行查询。

我已经在Objectify board 上询问过,回复既有用(使用翻译器)又不完整(我找不到任何关于如何使用翻译器界面的文档)。

那么我现在面临两个问题:

1) 仅将翻译器应用于特定对象(不保存嵌入对象,仅保存 id),而不是与同一种类相关的所有对象。

使用 JPA,可以使用 @Converter 注释来发出此请求 所以,通过这种设计,类应该是这样的

@Entity
public class ClassA {

    @Id
    public Long id;

    @MyCustomTranslator
    public ClassB classbObject;

    // Default behaviour
    public ClassB embeddedObject;
}

我需要指定我不需要混合持久性,Java 变量将始终以相同的方式保存(嵌入或只是 id),但我需要区分一个类(例如)是否有两个变量相同的类型,或者我在 2 个不同的类中有相同的变量类型

2) 替代第一点,将决策移到 Translator 本身中,因此“将 pojo 转换为 id”代码使用编码假设来确定对象是否应存储为默认嵌入或将其转换为 ID 值.

在没有文档的情况下,我试图从 Objectify 源代码中模拟已经存在的翻译器,但我无法获得一个可以工作的翻译器。


这是我第一次尝试

public class TestTranslator implements TranslatorFactory<ClassA, Long> {

    @Override
    public Translator<ClassA, Long> create(TypeKey<ClassA> arg0, CreateContext arg1, Path arg2) {
        return new CustomTranslator();
    }

    public static class CustomTranslator implements Translator<ClassA, Long> {
        @Override
        public ClassA load(Long arg0, LoadContext arg1, Path arg2) throws SkipException {
            ClassA a = new ClassA();
            a.id = arg0;
            // Other custom code
            return a;
        }

        @Override
        public Long save(ClassA arg0, boolean arg1, SaveContext arg2, Path arg3) throws SkipException {
            return arg0.id;
        }
    }
}

这是我用于初始化的代码

ObjectifyService.factory().getTranslators().add(new TestTranslator());

ObjectifyService.register(ClassA.class);
ObjectifyService.register(ClassB.class);

这不起作用,因为我在初始化期间得到了很长的堆栈跟踪,主要错误

TestTranslator$CustomTranslator cannot be cast to com.googlecode.objectify.impl.translate.ClassTranslator

另外,这并不能解决我的第 1 个问题,所以我无法决定是正常嵌入对象还是应用我的翻译器。


第二次尝试,使用 Translator 的另一个超类

public class TestValueTranslator extends ValueTranslatorFactory<ClassA, Long> {
    public TestValueTranslator() {
        super(ClassA.class);
    }

    @Override
    protected ValueTranslator<ClassA, Long> createValueTranslator(TypeKey<ClassA> tk, CreateContext ctx, Path path) {
        return new ValueTranslator<ClassA, Long>(Long.class) {
            @Override
            protected ClassA loadValue(Long value, LoadContext ctx, Path path) throws SkipException {
                ClassA a = new ClassA();
                a.id = value;
                // Other custom code
                return a;
            }

            @Override
            protected Long saveValue(ClassA value, boolean index, SaveContext ctx, Path path) throws SkipException {
                return value.id;
            }
        };
    }
}

和上面一样的错误

TestValueTranslator$1 cannot be cast to com.googlecode.objectify.impl.translate.ClassTranslator

Objectify 似乎在强迫我使用 ClassTranslator,我试图实现它

public class TestClassTranslatorFactory extends ClassTranslatorFactory<ClassA> {

    @Override
    public ClassTranslator<ClassA> create(TypeKey<ClassA> tk, CreateContext ctx, Path path) {
        // ????
        return super.create(tk, ctx, path);
    }

    public class TestClassTranslator extends ClassTranslator<ClassA> {

        public TestClassTranslator(Class<ClassA> declaredClass, Path path, Creator<ClassA> creator, Populator<ClassA> populator) {
            super(declaredClass, path, creator, populator);
        }

        @Override
        public ClassA loadSafe(PropertyContainer arg0, LoadContext arg1, Path arg2) throws SkipException {
            EmbeddedEntity e = (EmbeddedEntity) arg0;
            Long id = (Long) e.getProperty("id");

            ClassA a = new ClassA();
            a.id = id;
            // Other custom code
            return a;
        }

        @Override
        public PropertyContainer saveSafe(ClassA arg0, boolean arg1, SaveContext arg2, Path arg3) throws SkipException {
            EmbeddedEntity e = new EmbeddedEntity();
            e.setProperty("id", arg0.id);
            return e;
        }
    }
}

这里有两个问题: 1) 我不明白如何在TestClassTranslatorFactory 构造函数中创建TestClassTranslator 对象。 2)即使这个类有效,我也不得不创建一个嵌入式实体(里面有id),我不能保存为纯长(o List)。因此,我不确定是否可以完成索引部分。

最后,2个问题: 1) 是否有正确的Translator 将类对象转换为纯ID? 2) 转换器如何只应用于某些相同类型的变量?

【问题讨论】:

    标签: java google-app-engine entity objectify pojo


    【解决方案1】:

    这里发生了很多事情,stackoverflow 可能是一种糟糕的来回对话格式,最终会让你到达你想去的地方。有一个google group 可能会更有用。

    您的第一个问题是TranslatorFactory 的合同要求如果TypeKey 不适合该工厂,create() 返回 null。注册时,按顺序尝试工厂,直到其中一个成功; Translator 然后成为快速但静态元模型的一部分,用于在 POJO 和实体之间进行转换。通过始终返回翻译,您在此发现期间“声明”了所有内容。所以检查类型是否正确,如果类型不适合你,则返回 null。

    另一个有用的知识是有一个@Translate 注释,您可以在特定字段上使用它,这将强制它们由特定的翻译器处理。您可以将其与未提前注册的工厂一起使用,因此您可以有选择地修改某些字段的行为,而不会影响该类型的其他用途。

    【讨论】:

      【解决方案2】:

      使用@Translate 解决,可应用于特定字段

      【讨论】:

        猜你喜欢
        • 2017-01-13
        • 1970-01-01
        • 2015-09-20
        • 2012-08-02
        • 2021-05-06
        • 1970-01-01
        • 2011-01-06
        • 2013-06-21
        • 2011-08-23
        相关资源
        最近更新 更多