Hibernate + spring-data:WrongClassException - 具有id的对象不是指定的子类

时间:2013-02-05 13:06:41

标签: hibernate inheritance spring-data

我有以下课程结构:

Class Diagramm

我有一个用于AbstractCompound的弹簧数据存储库(使用QueryDSL):

@Repository
public interface AbstractCompoundRepository<T extends AbstractCompound>
    extends JpaRepository<T, Long>, QueryDslPredicateExecutor<T> {
}

以及调用该存储库的Service类:

@Service
@Transactional
public class CompoundServiceImpl<T extends AbstractCompound>
    implements CompoundService<T> {

    @Autowired
    private AbstractCompoundRepository<T> compoundRepository;    

    private Class<T> compoundClass;

    private Class<? extends EntityPathBase<T>> compoundQueryClass;

    private PathBuilder<T> pathBuilder;   

    @Autowired
    public CompoundServiceImpl(Class<T> compoundClass,
            Class<? extends EntityPathBase<T>> compoundQueryClass) {
        this.compoundClass = compoundClass;
        this.compoundQueryClass = compoundQueryClass;
        String path = compoundClass.getSimpleName();
        pathBuilder = new PathBuilder<>(compoundClass, path);
    }       

    @Override
    public T findOne(Predicate predicate) {
        return compoundRepository.findOne(predicate);
    }
    //...snipped...
}

ApplicationContext.xml为每个具体类定义一个服务(bean)。

如果我运行测试,我会得到提到的异常:

WrongClassException - object with id was not of the specified subclass RegistrationCompound

我可以验证是否使用正确的compoundClass调用了正确的服务。但是,存储库似乎总是期望RegisterCompound。

我认为这是导致存储库自动装配的原因。我怀疑只创建了一个实例,该实例需要一个RegistrationCompound。我的问题是如何为每个服务类提供特定于类型的存储库?是否有可能拥有这样的通用存储库?

编辑:

现在我开始生气了。我想要的,我的设计,对我来说似乎非常基本。但是,每个这样的框架都使用了与示例中略有不同的框架,它只是打破了所有目的。我想知道人们如何将这个用于任何不完全简单的事情。

我确实按照遗嘱的建议重构某些事情。但是我仍然得到WrongClassException。问题是还有一个带有自定义行为的类AbstractCompoundRepositoryImpl。并且该类中的所有方法都会引发这种情况。很明显,spring仍然只创建了一个这样的实例(总是使用RegistrationCompound作为Type)。问题是这个类包含了我试图抽象出来的实际复杂的逻辑。如果必须为每个具体类别单独实现,则无法用于我的目的。我不明白。我告诉Spring要创建2个不同的存储库,所以请按照我告诉你的春天做什么?好?严重...

编辑2:

还有一些竞争条件。它并不总是与抛出此错误的测试相同,它根据复合类型弹簧决定用于创建存储库(而不是创建2,就像我告诉它要做的那样)而变化最大...

1 个答案:

答案 0 :(得分:0)

我也怀疑你的问题的原因是@autowired存储库。

我会改变你的代码:

public abstract class AbstractCompoundService<T extends AbstractCompound>
implements CompoundService<T> {
  ...
  protected abstract AbstractCompoundRepository<T> getCompoundRepository();

  @Override
  public T findOne(Predicate predicate) {
    return getCompoundRepository().findOne(predicate);
  }
  ...
}
public RegistrationCompoundService extends AbstractCompoundService<RegistrationCompound> {

   @Autowired
   RegistrationCompoundRepository registrationCompoundRepository;

   protected AbstractCompoundRepository<RegistrationCompound> getCompoundRepository(){
      return registrationCompoundRepository;
   }
}