我有这样的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上问过,并且回复既有用(使用Translator),又不完整(我找不到任何有关如何使用Translator接口的文档)。

那我现在面临两个问题:

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)作为第一点的替代方案,将决策移到转换器本身中,因此“将pojo转换为id”代码使用编码假设来确定是否应将对象存储为默认嵌入对象或将其转换为ID值。

没有文档,我试图从Objectify源代码模仿已经存在的Translator,但是我无法获得有效的Translator。



这是我尝试过的第一次尝试

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)我不明白如何在TestClassTranslator构造函数中创建TestClassTranslatorFactory对象。
2)即使该类起作用,我也被迫创建一个嵌入式实体(其ID位于其中),并且我无法将其另存为纯Long(o列表)。因此,我不确定是否可以完成索引部分。

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

最佳答案

这里发生了很多事情,stackoverflow对于来回对话可能是一种糟糕的格式,最终将使您到达想要的位置。有一个google group可能会更有用。

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

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

09-08 09:04