简体   繁体   English

Objectify转换器作为JPA属性转换器

[英]Objectify Translator as JPA Attribute Converter

I have a POJO structure like this 我有这样的POJO结构

@Entity
public class ClassA {

    @Id
    public Long id;

    public ClassB classbObject;
}

And another class 还有另一堂课

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

    public String fieldA;

    public String fieldB;
}

Now, basing on custom conditions, I need to save the classbObject like an embedded one (default behaviour of Objectify) or only the id property (here it comes the Translator ). 现在,基于自定义条件,我需要将classbObject保存为嵌入式对象(默认行为为Objectify)或仅保存id属性(此处为Translator )。

This condition is also applied even with a single field ClassA or a multiple field List<ClassA> 即使对于单个字段ClassA或多个字段List<ClassA>此条件也适用

If the object will be saved as just ID, I also need to Index it to make query on that. 如果对象将被保存为ID,我还需要对其进行索引以对此进行查询。

I already asked on the Objectify board and the reply is both useful (use the Translator) and incomplete (I can't find any documentation on how to use the Translator interface). 我已经在Objectify板上问过,答复既有用(使用Translator),又不完整(我找不到任何有关如何使用Translator接口的文档)。

Two problem then I'm facing now: 那我现在面临两个问题:

1) Apply the translator only to specific objects (not saving the embedded object but just the id) and not all the objects related to the same kind. 1)仅将翻译器应用于特定对象(不保存嵌入的对象,而仅保存id),而不是将所有与同一种类相关的对象应用。

With JPA this request can be made with the use of the @Converter annotation So, with this design, the class should be something like this 使用JPA时,可以使用@Converter批注来发出此请求。因此,使用此设计,该类应类似于以下内容

@Entity
public class ClassA {

    @Id
    public Long id;

    @MyCustomTranslator
    public ClassB classbObject;

    // Default behaviour
    public ClassB embeddedObject;
}

I need to specify that I don't need an hybrid persistence, a Java variable will be always save in the same way (embedded or just id), but I need to differentiate if a class (for example) has two variables of the same type or I have the same variable type in 2 differente classes 我需要指定不需要混合持久性,Java变量将始终以相同的方式保存(嵌入或仅保存id),但是我需要区分一个类(例如)是否具有两个相同的变量类型或我在2个差异类中具有相同的变量类型

2) Alternatively of the first point, moving the decision in the Translator itself, so the "convert pojo to id" code use the coded assumptions to determine if the object should be stored as default embedded or convert it to a ID value. 2)作为第一点的替代方案,将决策移到转换器本身中,因此“将pojo转换为id”代码使用编码假设来确定是否应将对象存储为默认嵌入对象或将其转换为ID值。

Without documentation I tried to emulate the already existing Translator from Objectify source code, but I cannot get a working one. 没有文档,我试图从Objectify源代码模仿已经存在的Translator,但是我无法获得有效的Translator。


This is the first attempt I tried 这是我尝试过的第一次尝试

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;
        }
    }
}

Here is the code that I use for init 这是我用于初始化的代码

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

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

This does not work because I get a very long stacktrace during the init, with the main error 这是行不通的,因为我在初始化过程中得到了很长的堆栈跟踪信息,并且出现了主要错误

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

Also, this is not solving my number 1 problem, so I cannot decide if embed the Object as normal or apply my Translator. 另外,这不能解决我的1号问题,因此我无法确定是将对象正常嵌入还是应用我的翻译器。


Second attempt, with another superclass of Translator 第二次尝试,使用另一个超类的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;
            }
        };
    }
}

Same error as above 与上述相同的错误

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

It seems that Objectify is forcing me to use a ClassTranslator , which I tried to implement 似乎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;
        }
    }
}

Two problems here: 1) I cannot understand how to create a TestClassTranslator object in the TestClassTranslatorFactory constructor. 这里有两个问题:1)我不明白如何在TestClassTranslatorFactory构造函数中创建TestClassTranslator对象。 2) Even if this class works, I'm force to create an embedded entity (with the id inside) and I cannot save as a pure Long (o List). 2)即使该类起作用,我也被迫创建一个嵌入式实体(其ID位于其中),并且我无法将其另存为纯Long(o列表)。 Because of that the indexing part I'm not sure can be accomplished. 因此,我不确定是否可以完成索引部分。

At the end, 2 questions: 1) Is there a correct Translator to convert a class object to the pure id? 最后,有两个问题:1)是否有正确的Translator器将类对象转换为纯id? 2) How can the converter be applied only to certain variables of the same type? 2)只能将转换器应用于相同类型的某些变量吗?

There's a lot going on here and stackoverflow is probably a poor format for the back-and-forth dialogue which will eventually get you where you want to be. 这里发生了很多事情,stackoverflow对于来回对话可能是一种糟糕的格式,最终将使您到达想要的位置。 There is a google group which will likely be more useful. 有一个谷歌组可能会更有用。

Your first issue is that the contract for TranslatorFactory requires that create() return null if the TypeKey is not appropriate for that factory. 您的第一个问题是,如果TypeKey不适合该工厂,那么TranslatorFactory的合同要求create()返回null。 At registration time, factories are tried in order until one of them succeeds; 在注册时,将依次尝试工厂,直到其中一个成功为止。 the Translator then becomes part of a fast-but-static metamodel for translating between POJOs and Entities. 然后, Translator将成为快速但静态的元模型的一部分,用于在POJO和实体之间进行翻译。 By always returning a translator, you're "claiming" everything during this discovery period. 通过始终返回翻译人员,您就可以在此发现期间“声明”所有内容。 So check if the type is correct and return null if the type is not for you. 因此,请检查类型是否正确,如果类型不适合您,则返回null。

Another useful piece of knowledge is that there is a @Translate annotation that you can use on specific fields which will force them to be processed by a particular translator. 另一个有用的知识是,您可以在特定字段上使用@Translate注释,这将迫使它们由特定的翻译程序处理。 You can use this with factories that you do not register in advance, so you can selectively modify the behavior of certain fields without affecting other uses of that type. 您可以将其与未事先注册的工厂一起使用,因此可以有选择地修改某些字段的行为,而不会影响该类型的其他用途。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM