OPENJPA-765 Check for isInsertable and isUpdatable in HandlerFieldStrategy

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@712928 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Dick 2008-11-11 03:44:43 +00:00
parent 75b9ca7fa3
commit 02608cc658
8 changed files with 294 additions and 62 deletions

View File

@ -193,8 +193,9 @@ public abstract class AbstractUpdateManager
BitSet dirty = sm.getDirty();
for (int i = 0; i < fields.length; i++) {
if (dirty.get(fields[i].getIndex())
&& !bufferCustomInsert(fields[i], sm, store, customs))
&& !bufferCustomInsert(fields[i], sm, store, customs)) {
fields[i].insert(sm, store, rowMgr);
}
}
if (sup == null) {
Version vers = mapping.getVersion();
@ -279,8 +280,9 @@ public abstract class AbstractUpdateManager
FieldMapping[] fields = mapping.getDefinedFieldMappings();
for (int i = 0; i < fields.length; i++) {
if (dirty.get(fields[i].getIndex())
&& !bufferCustomUpdate(fields[i], sm, store, customs))
&& !bufferCustomUpdate(fields[i], sm, store, customs)) {
fields[i].update(sm, store, rowMgr);
}
}
ClassMapping sup = mapping.getJoinablePCSuperclassMapping();

View File

@ -122,27 +122,31 @@ public class HandlerFieldStrategy
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
if (row != null) {
Object value = sm.fetch(field.getIndex());
if (!HandlerStrategies.set(field, value, store, row, _cols, _io,
field.getNullValue() == FieldMapping.NULL_NONE))
if (field.getValueStrategy() != ValueStrategies.AUTOASSIGN)
throw new UserException(_loc.get("cant-set-value",
row.getFailedObject(), field, value));
if (field.getColumnIO().isInsertable(0, false)) {
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
if (row != null) {
Object value = sm.fetch(field.getIndex());
if (!HandlerStrategies.set(field, value, store, row, _cols,
_io, field.getNullValue() == FieldMapping.NULL_NONE))
if (field.getValueStrategy() != ValueStrategies.AUTOASSIGN)
throw new UserException(_loc.get("cant-set-value", row
.getFailedObject(), field, value));
}
}
}
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE);
if (row != null){
Object value = sm.fetch(field.getIndex());
if (!HandlerStrategies.set(field, value, store, row, _cols, _io,
field.getNullValue() == FieldMapping.NULL_NONE))
if (field.getValueStrategy() != ValueStrategies.AUTOASSIGN)
throw new UserException(_loc.get("cant-set-value",
row.getFailedObject(), field, value));
if (field.getColumnIO().isUpdatable(0, false)) {
Row row = field.getRow(sm, store, rm, Row.ACTION_UPDATE);
if (row != null) {
Object value = sm.fetch(field.getIndex());
if (!HandlerStrategies.set(field, value, store, row, _cols,
_io, field.getNullValue() == FieldMapping.NULL_NONE))
if (field.getValueStrategy() != ValueStrategies.AUTOASSIGN)
throw new UserException(_loc.get("cant-set-value", row
.getFailedObject(), field, value));
}
}
}
@ -154,7 +158,7 @@ public class HandlerFieldStrategy
public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch) {
if ((type == Select.TYPE_JOINLESS && sel.isSelected(field.getTable()))
|| (_load && type == sel.TYPE_TWO_PART))
|| (_load && type == Select.TYPE_TWO_PART))
return 1;
return 0;
}

View File

@ -0,0 +1,66 @@
/*
* 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.nullity;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
public abstract class AbstractNullityTestCase extends SingleEMFTestCase {
protected static boolean NEW = true;
/**
* Asserts that the given instance can not be committed.
*/
void assertCommitFails(Object pc, boolean isNew,
Class<? extends Exception> expected) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
if (isNew) {
em.persist(pc);
}
else {
em.merge(pc);
}
try {
em.getTransaction().commit();
fail();
} catch (Exception e) {
if (!expected.isAssignableFrom(e.getClass())) {
e.printStackTrace();
fail("Expected " + expected.getName());
}
}
}
void assertCommitSucceeds(Object pc, boolean isNew) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
if (isNew)
em.persist(pc);
else
em.merge(pc);
try {
em.getTransaction().commit();
} catch (RuntimeException e) {
e.printStackTrace();
fail();
}
}
}

View File

@ -27,7 +27,32 @@ import java.io.Serializable;
*
*/
public class BlobValue implements Serializable {
private static final long serialVersionUID = 833553627832894685L;
private String strVal;
private int intVal;
private byte[] bytes;
public String getStrVal() {
return strVal;
}
public void setStrVal(String strVal) {
this.strVal = strVal;
}
public int getIntVal() {
return intVal;
}
public void setIntVal(int intVal) {
this.intVal = intVal;
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
}

View File

@ -147,4 +147,8 @@ public class NullValues {
public void setNotOptionalBlob(BlobValue notOptionalBlob) {
this.notOptionalBlob = notOptionalBlob;
}
public int getVersion() {
return version;
}
}

View File

@ -18,13 +18,10 @@
*/
package org.apache.openjpa.persistence.nullity;
import javax.persistence.EntityManager;
import javax.persistence.RollbackException;
import org.apache.openjpa.persistence.InvalidStateException;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* Test @Basic(optional=true|false) and @Column(nullable=true|false)
@ -34,8 +31,7 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase;
*
* @author Pinaki Poddar
*/
public class TestBasicFieldNullity extends SingleEMFTestCase {
private static boolean NEW = true;
public class TestBasicFieldNullity extends AbstractNullityTestCase {
public void setUp() {
setUp(CLEAR_TABLES, NullValues.class);
@ -116,44 +112,6 @@ public class TestBasicFieldNullity extends SingleEMFTestCase {
pc.setNotNullableBlob(null);
assertCommitFails(pc, !NEW, RollbackException.class);
}
/**
* Asserts that the given instance can not be committed.
*/
void assertCommitFails(Object pc, boolean isNew, Class expected) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
if (isNew)
em.persist(pc);
else {
Object merged = em.merge(pc);
}
try {
em.getTransaction().commit();
fail();
} catch (Exception e) {
if (!expected.isAssignableFrom(e.getClass())) {
e.printStackTrace();
fail("Expected " + expected.getName());
}
}
}
void assertCommitSucceeds(Object pc, boolean isNew) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
if (isNew)
em.persist(pc);
else
em.merge(pc);
try {
em.getTransaction().commit();
} catch (RuntimeException e) {
e.printStackTrace();
fail();
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.nullity;
import javax.persistence.EntityManager;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.sql.AbstractDB2Dictionary;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
/**
* Testcase that verifies that null checking is omitted for "read only" fields.
* An example use case is a Date field that is set by the database (although in
* that case the field would be updateable=false and insertable=false).
*/
public class TestReadOnlyNullity extends AbstractNullityTestCase {
private boolean skip = false;
public void setUp() {
OpenJPAEntityManagerFactorySPI emf = createEMF(new Object[] {});
if (((JDBCConfiguration) emf.getConfiguration())
.getDBDictionaryInstance() instanceof AbstractDB2Dictionary) {
setUp(CLEAR_TABLES, TimestampedEntity.class);
} else {
skip = true;
}
}
/**
* Test that a non-insertable field may be set to null. This test is skipped
* for non-db2 databases.
*/
public void testNonInsertableBlobDoesNotFail() {
if (!skip) {
TimestampedEntity pc = new TimestampedEntity();
pc.setNonInsertableNonNullableDate(null);
assertCommitSucceeds(pc, NEW);
}
// else no-op
}
/**
* Test that a non-updatable field may be set to null. This test is skipped
* for non-db2 databases.
*/
public void testNonUpdatableBlobDoesNotFail() {
if (!skip) {
TimestampedEntity pc = new TimestampedEntity();
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(pc);
em.getTransaction().commit();
em.clear();
pc.setNonUpdatableNonNullableDate(null);
assertCommitSucceeds(pc, !NEW);
}
// else no-op
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.nullity;
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;
/**
* This Entity contains two date fields which are updated by the database. The
* fields are non-insertable and non-updatable respectively making them read
* only in many situations. The fields should be ignored when persisting or
* updating an entity (again respectively).
*
* <P>
* <b>The syntax used for the database to generate the date column is specific
* to Derby and DB2. Any testcase which uses this entity must ensure that one of
* those databases is used, or use pre-existing tables</b>
* </P>
*/
@Entity
public class TimestampedEntity {
@Id
@GeneratedValue
private int id;
@Version
private int version;
@Column(nullable = false, insertable = false,
columnDefinition = "DATE default '2008-01-01'")
private Date nonInsertableNonNullableDate;
@Column(nullable = false, updatable = false,
columnDefinition = "DATE default '2008-01-01'")
private Date nonUpdatableNonNullableDate;
public TimestampedEntity() {
setNonUpdatableNonNullableDate(new Date(52349606));
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getNonInsertableNonNullableDate() {
return nonInsertableNonNullableDate;
}
public void setNonInsertableNonNullableDate(
Date nonInsertableNonNullableDate) {
this.nonInsertableNonNullableDate = nonInsertableNonNullableDate;
}
public Date getNonUpdatableNonNullableDate() {
return nonUpdatableNonNullableDate;
}
public void setNonUpdatableNonNullableDate(
Date nonUpdatableNonNullableDate) {
this.nonUpdatableNonNullableDate = nonUpdatableNonNullableDate;
}
}