OPENJPA-272. Committing the changes to allow @GeneratedValue to detect and report if initial values and/or setters were called on fields marked with @GeneratedValue. New testcases were also provided.

Also had to update an existing testcase (TestSharedMappedSuperclassIdValue) and associated Entities because it was breaking the contract put in place.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@562987 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Kevin W. Sutter 2007-08-05 23:34:06 +00:00
parent c34fb4e80e
commit 9382677eb1
10 changed files with 359 additions and 19 deletions

View File

@ -574,10 +574,15 @@ public class StateManagerImpl
return assign && assignObjectId(!preFlushing, preFlushing);
}
// don't assign values to fields with non-default values already
if (fmd.getValueStrategy() == ValueStrategies.NONE
|| !isDefaultValue(field))
// Just return if there's no value generation strategy
if (fmd.getValueStrategy() == ValueStrategies.NONE)
return false;
// Throw exception if field already has a value assigned.
// @GeneratedValue overrides POJO initial values and setter methods
if (!isDefaultValue(field) && !fmd.is_generated())
throw new InvalidStateException(_loc.get(
"existing-value-override-excep", fmd.getFullName(false)));
// for primary key fields, assign the object id and recache so that
// to the user, so it looks like the oid always matches the pk fields
@ -585,8 +590,10 @@ public class StateManagerImpl
return assignObjectId(!preFlushing, preFlushing);
// for other fields just assign the field or flush if needed
if (_broker.getStoreManager().assignField(this, field, preFlushing))
if (_broker.getStoreManager().assignField(this, field, preFlushing)) {
fmd.set_generated(true);
return true;
}
if (!preFlushing)
_broker.flush();
return !preFlushing;

View File

@ -30,6 +30,7 @@ import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.enhance.Reflection;
import org.apache.openjpa.kernel.ObjectIdStateManager;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StateManagerImpl;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
@ -49,6 +50,8 @@ public class ApplicationIds {
private static final Localizer _loc = Localizer.forPackage
(ApplicationIds.class);
private static final Localizer _loc2 = Localizer.forPackage
(StateManagerImpl.class);
/**
* Return the primary key values for the given object id. The values
@ -430,15 +433,25 @@ public class ApplicationIds {
}
/**
* Assign generated values to given fields.
* Assign generated values to given primary key fields.
*/
private static boolean assign(OpenJPAStateManager sm, StoreManager store,
FieldMetaData[] pks, boolean preFlush) {
for (int i = 0; i < pks.length; i++)
if (pks[i].getValueStrategy() != ValueStrategies.NONE
&& sm.isDefaultValue(pks[i].getIndex())
&& !store.assignField(sm, pks[i].getIndex(), preFlush))
return false;
// If we are generating values...
if (pks[i].getValueStrategy() != ValueStrategies.NONE) {
// If a value already exists on this field, throw exception.
// This is considered an application coding error.
if (!sm.isDefaultValue(pks[i].getIndex()))
throw new InvalidStateException(_loc2.get(
"existing-value-override-excep", pks[i]
.getFullName(false)));
// Assign the generated value
if (store.assignField(sm, pks[i].getIndex(), preFlush))
pks[i].set_generated(true);
else
return false;
}
return true;
}

View File

@ -368,3 +368,8 @@ null-fg: Attempt to add null/empty fetch group name to fetch configuration.
null-field: Attempt to add null/empty field name to fetch configuration.
container-projection: Query projections cannot include array, collection, or \
map fields. Invalid query: "{0}"
existing-value-override-excep: The generated value processing detected an \
existing value assigned to this field: {0}. This existing value was either \
provided via an initializer or by calling the setter method. You either need \
to remove the @GeneratedValue annotation or modify the code to remove the \
initializer processing.

View File

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.generationtype;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class GeneratedValues {
@Id
@GeneratedValue
private int id;
@GeneratedValue
private long field;
public GeneratedValues() {
super();
}
public GeneratedValues(int id, long field) {
super();
this.id = id;
this.field = field;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getField() {
return field;
}
public void setField(long field) {
this.field = field;
}
}

View File

@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.generationtype;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.InvalidStateException;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
public class TestGeneratedValues extends SingleEMFTestCase {
public void setUp() {
setUp(GeneratedValues.class, CLEAR_TABLES);
}
public void testDefaultValues() {
EntityManager em = emf.createEntityManager();
GeneratedValues gv = new GeneratedValues();
GeneratedValues gv2 = new GeneratedValues();
em.getTransaction().begin();
em.persist(gv);
em.persist(gv2);
em.getTransaction().commit();
em.refresh(gv);
em.refresh(gv2);
assertFalse(gv.getId() == gv2.getId());
assertFalse(gv.getField() == gv2.getField());
}
public void testInitialValues() {
EntityManager em = emf.createEntityManager();
GeneratedValues gv = new GeneratedValues(7, 9);
try {
em.getTransaction().begin();
em.persist(gv);
em.getTransaction().commit();
} catch (InvalidStateException ise) {
// expected result
return;
}
// should not get here...
fail();
}
public void testIdSetter() {
EntityManager em = emf.createEntityManager();
GeneratedValues gv = new GeneratedValues();
gv.setId(3);
try {
em.getTransaction().begin();
em.persist(gv);
em.getTransaction().commit();
} catch (InvalidStateException ise) {
// expected result
return;
}
// should not get here...
fail();
}
public void testFieldSetter() {
EntityManager em = emf.createEntityManager();
GeneratedValues gv = new GeneratedValues();
gv.setField(5);
try {
em.getTransaction().begin();
em.persist(gv);
em.getTransaction().commit();
} catch (InvalidStateException ise) {
// expected result
return;
}
// should not get here...
fail();
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.inheritance;
import javax.persistence.Entity;
@Entity
public class NoGenEntityL3
extends NoGenMappedSuperclassL2 {
private int l3data;
public int getL3Data() {
return l3data;
}
public void setL3Data(int data) {
l3data = data;
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.inheritance;
import javax.persistence.Entity;
@Entity
public class NoGenEntityL3Sibling
extends NoGenMappedSuperclassL2 {
private int siblingl3data;
public int getSiblingL3Data() {
return siblingl3data;
}
public void setSiblingL3Data(int data) {
siblingl3data = data;
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.inheritance;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class NoGenMappedSuperclassBase {
@Id
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.inheritance;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class NoGenMappedSuperclassL2
extends NoGenMappedSuperclassBase {
private int l2data;
public int getL2Data() {
return l2data;
}
public void setL2Data(int data) {
l2data = data;
}
}

View File

@ -33,15 +33,16 @@ public class TestSharedMappedSuperclassIdValue
extends SingleEMFTestCase {
public void setUp() {
setUp(MappedSuperclassBase.class, MappedSuperclassL2.class,
EntityL3.class, EntityL3Sibling.class);
setUp(CLEAR_TABLES, NoGenMappedSuperclassBase.class,
NoGenMappedSuperclassL2.class, NoGenEntityL3.class,
NoGenEntityL3Sibling.class);
EntityL3 ent = new EntityL3();
ent.setId(1);
NoGenEntityL3 ent = new NoGenEntityL3();
ent.setId(1L);
ent.setL2Data(99);
ent.setL3Data(100);
EntityL3Sibling sib = new EntityL3Sibling();
sib.setId(1);
NoGenEntityL3Sibling sib = new NoGenEntityL3Sibling();
sib.setId(1L);
sib.setL2Data(100);
sib.setSiblingL3Data(101);
@ -55,12 +56,12 @@ public class TestSharedMappedSuperclassIdValue
public void testFind() {
EntityManager em = emf.createEntityManager();
EntityL3 ent = em.find(EntityL3.class, 1L);
NoGenEntityL3 ent = em.find(NoGenEntityL3.class, 1L);
assertNotNull(ent);
assertEquals(99, ent.getL2Data());
assertEquals(100, ent.getL3Data());
EntityL3Sibling sib = em.find(EntityL3Sibling.class, 1L);
NoGenEntityL3Sibling sib = em.find(NoGenEntityL3Sibling.class, 1L);
assertNotNull(sib);
assertEquals(100, sib.getL2Data());
assertEquals(101, sib.getSiblingL3Data());
@ -70,10 +71,10 @@ public class TestSharedMappedSuperclassIdValue
public void testGetReference() {
EntityManager em = emf.createEntityManager();
EntityL3 ent = em.getReference(EntityL3.class, 1L);
NoGenEntityL3 ent = em.getReference(NoGenEntityL3.class, 1L);
assertNotNull(ent);
EntityL3Sibling sib = em.getReference(EntityL3Sibling.class, 1L);
NoGenEntityL3Sibling sib = em.getReference(NoGenEntityL3Sibling.class, 1L);
assertNotNull(sib);
assertEquals(99, ent.getL2Data());