它适用于生产,但在Arquillian / Junit测试中使用InvalidStateException(非托管对象)

时间:2018-02-27 23:30:15

标签: rest jpa openjpa tomee

ClassA和ClassB之间存在ManyToMany关系。 ClassA拥有ClassB对象的集合,而ClassB对ClassA一无所知。 A类的相关部分看起来像这样:

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="ClassA_ClassB_JoinTable",
        joinColumns=@JoinColumn(name="classAId"),
        inverseJoinColumns=@JoinColumn(name="classBId"))
private ArrayList<ClassB> classBReferences = new ArrayList<ClassB>();

我有一个简单的CrudDao,其相关代码是:

@Singleton
public class CrudDao {

    @PersistenceContext(unitName = "myDatabaseName")
    private EntityManager em;

    public <E> E create(E e) {
        em.persist(e);
        return e;
    }
}

我创造了一个人为的/简化的例子来说明我遇到的问题。我写了一个简化的REST端点,如下所示:

@Path("/simplified")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public class SimplifiedService {

    @Inject
    private CrudDao crudDao;

    @GET
    @Path("")
    public Response watchItCrash() {

        ClassB classB = new ClassB();
        classB.setAttribute("Blah!");
        crudDao.create(classB);

        ClassA classA = new ClassA();
        classA.getClassBReferences().add(classB);
        crudDao.create(classA);

        return Response.ok().build();
    }
}

当我站起来使用我的REST服务(使用TomEE)时,我可以进行GET调用,一切都运行良好。但是,我也尝试使用Arquillian和JUnit来测试我的REST端点,这是我遇到麻烦的地方。

我的Arquillian / JUnit测试如下所示:

@RunWith(Arquillian.class)
public class SimplifiedServiceIT {

    @ArquillianResource
    private URL webappUrl;

    @Deployment()
    public static WebArchive createDeployment() {
        return ShrinkWrap.create(WebArchive.class)
                .addClasses(SimplifiedService.class, CrudDao.class)
                .addAsWebInfResource("META-INF/persistence.xml")
                .addAsWebInfResource("test-resources.xml", "resources.xml")
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Test
    public void testGetRoles() throws URISyntaxException {
        URI uri = webappUrl.toURI().resolve("simplified");
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(uri);
        Invocation.Builder builder = target.request();
        Response response = builder.get();
    }
}

现在显然我实际上并没有在这里测试任何东西,但是我可以看到GET调用成功完成,ClassB成功保持,但它无法持久化ClassA。这是我尝试持久化ClassA时出现的错误:

WARNING: Unexpected exception from beforeCompletion; transaction will roll back

<openjpa-2.4.0-r422266:1674604 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: Encountered unmanaged object "ClassB@56c6d515" in life cycle state  unmanaged while cascading persistence via field "ClassA.classBReferences<element:class ClassB>" during flush.  However, this field does not allow cascade persist. You cannot flush unmanaged objects or graphs that have persistent associations to unmanaged objects. Suggested actions:
a) Set the cascade attribute for this field to CascadeType.PERSIST or CascadeType.ALL (JPA annotations) or "persist" or "all" (JPA orm.xml), 
b) enable cascade-persist globally, 
c) manually persist the related field value prior to flushing. 
d) if the reference belongs to another context, allow reference to it by setting StoreContext.setAllowReferenceToSiblingContext().
FailedObject: ClassB@56c6d515

知道为什么它在'生产'中起作用但在Arquillian / UnitTest环境中失败了吗?

0 个答案:

没有答案