mirror of https://github.com/apache/openjpa.git
OPENJPA-1176 Add compatibility option to allow private persistent properties
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@794774 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c293165cb4
commit
5cb32680a9
|
@ -59,6 +59,7 @@ public class Compatibility {
|
|||
private boolean _cascadeWithDetach = false;
|
||||
private boolean _useJPA2DefaultOrderColumnName = true;
|
||||
private boolean _copyOnDetach = false;
|
||||
private boolean _privatePersistentProperties = false;
|
||||
|
||||
/**
|
||||
* Whether to require exact identity value types when creating object
|
||||
|
@ -354,4 +355,34 @@ public class Compatibility {
|
|||
public void setUseJPA2DefaultOrderColumnName(boolean useJPA2Name) {
|
||||
_useJPA2DefaultOrderColumnName = useJPA2Name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether OpenJPA allows private, non-transient properties to be
|
||||
* persistent. Prior to OpenJPA 2.0, if property access was used,
|
||||
* private properties were considered persistent. This is contrary to the
|
||||
* JPA specification, which states that persistent properties must be
|
||||
* public or protected. The default value is false.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return true if non-transient private properties should be persistent
|
||||
*/
|
||||
public boolean getPrivatePersistentProperties() {
|
||||
return _privatePersistentProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether OpenJPA allows private, non-transient properties to be
|
||||
* persistent. Prior to OpenJPA 2.0, if property access was used,
|
||||
* private properties were considered persistent. This is contrary to the
|
||||
* JPA specification, which states that persistent properties must be
|
||||
* public or protected.
|
||||
*
|
||||
* @param privateProps true if non-transient private properties
|
||||
* should be persistent
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public void setPrivatePersistentProperties(boolean privateProps) {
|
||||
_privatePersistentProperties = privateProps;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,11 +375,13 @@ public abstract class AbstractMetaDataDefaults
|
|||
* or<br>
|
||||
* <code> public T isXXX()</code> where T is boolean or Boolean.<br>
|
||||
*/
|
||||
public static boolean isGetter(Method method) {
|
||||
public static boolean isGetter(Method method, boolean includePrivate) {
|
||||
if (method == null)
|
||||
return false;
|
||||
int mods = method.getModifiers();
|
||||
if (!Modifier.isPublic(mods)
|
||||
if (!(Modifier.isPublic(mods)
|
||||
|| Modifier.isProtected(mods)
|
||||
|| (Modifier.isPrivate(mods) && includePrivate))
|
||||
|| Modifier.isNative(mods)
|
||||
|| Modifier.isStatic(mods))
|
||||
return false;
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<exclude name="**/Unenhanced*.class" />
|
||||
<exclude name="**/AbstractUnenhanced*.class" />
|
||||
<exclude name="**/unenhanced/*.class" />
|
||||
<exclude name="**/persistence/property/PrivAccessModsEntity.class"/>
|
||||
</fileset>
|
||||
<openjpac>
|
||||
<classpath refid="cp" />
|
||||
|
@ -98,6 +99,14 @@
|
|||
</fileset>
|
||||
<config log="DefaultLevel=${openjpa.loglevel}" />
|
||||
</openjpac>
|
||||
|
||||
<!-- Enhance with private persistent properties compatibility option -->
|
||||
<openjpac>
|
||||
<config compatibility="PrivatePersistentProperties=true" />
|
||||
<classpath refid="cp" />
|
||||
<fileset dir="${project.build.testOutputDirectory}">
|
||||
<include name="**/persistence/property/PrivAccessModsEntity.class"/>
|
||||
</fileset>
|
||||
<config log="DefaultLevel=${openjpa.loglevel}" />
|
||||
</openjpac>
|
||||
</target>
|
||||
</project>
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.property;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
@Table(name="PUBPROT_TBL")
|
||||
public class AccessModsEntity {
|
||||
|
||||
private int id;
|
||||
|
||||
private String pubString;
|
||||
|
||||
private String protString;
|
||||
|
||||
private String privString;
|
||||
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setPubString(String pubString) {
|
||||
this.pubString = pubString;
|
||||
}
|
||||
|
||||
@Column(name="PUB_COL")
|
||||
public String getPubString() {
|
||||
return pubString;
|
||||
}
|
||||
|
||||
protected void setProtString(String protString) {
|
||||
this.protString = protString;
|
||||
}
|
||||
|
||||
@Column(name="PROT_COL")
|
||||
protected String getProtString() {
|
||||
return protString;
|
||||
}
|
||||
|
||||
private void setPrivString(String privString) {
|
||||
this.privString = privString;
|
||||
}
|
||||
|
||||
@Column(name="PRIV_COL")
|
||||
private String getPrivString() {
|
||||
return privString;
|
||||
}
|
||||
|
||||
// Transient public wrapper around private property
|
||||
public void setPubPrivString(String privString) {
|
||||
setPrivString(privString);
|
||||
}
|
||||
|
||||
// Transient public wrapper around private property
|
||||
@Transient
|
||||
public String getPubPrivString() {
|
||||
return getPrivString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.property;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
@Table(name="PRIV_TBL")
|
||||
public class PrivAccessModsEntity {
|
||||
|
||||
private int id;
|
||||
|
||||
private String pubString;
|
||||
|
||||
private String protString;
|
||||
|
||||
private String privString;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setPubString(String pubString) {
|
||||
this.pubString = pubString;
|
||||
}
|
||||
|
||||
@Column(name="PUB_COL")
|
||||
public String getPubString() {
|
||||
return pubString;
|
||||
}
|
||||
|
||||
protected void setProtString(String protString) {
|
||||
this.protString = protString;
|
||||
}
|
||||
|
||||
@Column(name="PROT_COL")
|
||||
protected String getProtString() {
|
||||
return protString;
|
||||
}
|
||||
|
||||
private void setPrivString(String privString) {
|
||||
this.privString = privString;
|
||||
}
|
||||
|
||||
@Column(name="PRIV_COL")
|
||||
private String getPrivString() {
|
||||
return privString;
|
||||
}
|
||||
|
||||
// Transient public wrapper around private property
|
||||
public void setPubPrivString(String privString) {
|
||||
setPrivString(privString);
|
||||
}
|
||||
|
||||
// Transient public wrapper around private property
|
||||
@Transient
|
||||
public String getPubPrivString() {
|
||||
return getPrivString();
|
||||
}
|
||||
}
|
|
@ -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.property;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
public class TestAccessMods
|
||||
extends SingleEMFTestCase {
|
||||
|
||||
public void setUp() {
|
||||
setUp(DROP_TABLES, AccessModsEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that by default, per JPA spec, non-transient public and
|
||||
* protected properties should be persistent. Private should not be
|
||||
* persistent.
|
||||
*/
|
||||
public void testAccessMods() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
AccessModsEntity ame = new AccessModsEntity();
|
||||
|
||||
// Set all properties
|
||||
ame.setPubString("Public");
|
||||
ame.setProtString("Protected");
|
||||
ame.setPubPrivString("Private");
|
||||
// Persist the entity. Public and protected properties should
|
||||
// get persisted. Private should not.
|
||||
em.getTransaction().begin();
|
||||
em.persist(ame);
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
ame = em.find(AccessModsEntity.class, ame.getId());
|
||||
assertNotNull(ame);
|
||||
assertEquals("Public", ame.getPubString());
|
||||
assertEquals("Protected", ame.getProtString());
|
||||
assertNull(ame.getPubPrivString());
|
||||
em.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.property;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
public class TestCompatAccessMods extends SingleEMFTestCase {
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp("openjpa.Compatibility", "PrivatePersistentProperties=true",
|
||||
DROP_TABLES, PrivAccessModsEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that with the PrivatePersistentProperties compatibility option
|
||||
* enabled, non-transient private properties are persistent.
|
||||
*
|
||||
* Note: PrivAccessModsEntity must also be enhanced with the compatibility
|
||||
* option set to true. This is currently handled in the test suite by
|
||||
* a separate enhancement task for PrivAccessModsEntity.
|
||||
*/
|
||||
public void testAccessMods() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
PrivAccessModsEntity pame = new PrivAccessModsEntity();
|
||||
|
||||
// Set all properties
|
||||
pame.setPubString("Public");
|
||||
pame.setProtString("Protected");
|
||||
pame.setPubPrivString("Private");
|
||||
// Persist the entity. All properties should be persisted.
|
||||
em.getTransaction().begin();
|
||||
em.persist(pame);
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
pame = em.find(PrivAccessModsEntity.class, pame.getId());
|
||||
assertNotNull(pame);
|
||||
assertEquals("Public", pame.getPubString());
|
||||
assertEquals("Protected", pame.getProtString());
|
||||
assertEquals("Private", pame.getPubPrivString());
|
||||
em.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -305,7 +305,8 @@ public class PersistenceMetaDataDefaults
|
|||
int access = determineExplicitAccessType(meta.getDescribedType());
|
||||
if (!AccessCode.isUnknown(access))
|
||||
return access;
|
||||
access = determineImplicitAccessType(meta.getDescribedType());
|
||||
access = determineImplicitAccessType(meta.getDescribedType(),
|
||||
meta.getRepository().getConfiguration());
|
||||
if (!AccessCode.isUnknown(access))
|
||||
return access;
|
||||
|
||||
|
@ -331,7 +332,8 @@ public class PersistenceMetaDataDefaults
|
|||
* Annotation can be placed on either fields or getters but not on both.
|
||||
* If no field or getter is annotated then UNKNOWN access code is returned.
|
||||
*/
|
||||
private int determineImplicitAccessType(Class<?> cls) {
|
||||
private int determineImplicitAccessType(Class<?> cls, OpenJPAConfiguration
|
||||
conf) {
|
||||
if (cls.isInterface()) // Managed interfaces
|
||||
return AccessCode.PROPERTY;
|
||||
Field[] allFields = AccessController.doPrivileged(J2DoPrivHelper.
|
||||
|
@ -339,6 +341,15 @@ public class PersistenceMetaDataDefaults
|
|||
Method[] methods = AccessController.doPrivileged(
|
||||
J2DoPrivHelper.getDeclaredMethodsAction(cls));
|
||||
List<Field> fields = filter(allFields, nonTransientFilter);
|
||||
/*
|
||||
* OpenJPA 1.x permitted private properties to be persistent. This is
|
||||
* contrary to the JPA 1.0 specification, which states that persistent
|
||||
* properties must be private or protected. OpenJPA 2.0+ will adhere
|
||||
* to the specification by default, but provides a compatibility
|
||||
* option to provide pre-2.0 behavior.
|
||||
*/
|
||||
getterFilter.setIncludePrivate(
|
||||
conf.getCompatibilityInstance().getPrivatePersistentProperties());
|
||||
List<Method> getters = filter(methods, getterFilter,
|
||||
nonTransientFilter);
|
||||
if (fields.isEmpty() && getters.isEmpty())
|
||||
|
@ -550,9 +561,11 @@ public class PersistenceMetaDataDefaults
|
|||
}
|
||||
try {
|
||||
// check for setters for methods
|
||||
Method setter = meta.getDescribedType().getMethod(
|
||||
"set" + StringUtils.capitalize(name),
|
||||
new Class[] {((Method) member).getReturnType()});
|
||||
Method setter = (Method) AccessController.doPrivileged(
|
||||
J2DoPrivHelper.getDeclaredMethodAction(
|
||||
meta.getDescribedType(), "set" +
|
||||
StringUtils.capitalize(name), new Class[] {
|
||||
((Method) member).getReturnType() }));
|
||||
if (setter == null && !isAnnotatedTransient(member)) {
|
||||
logNoSetter(meta, name, null);
|
||||
return false;
|
||||
|
@ -716,8 +729,19 @@ public class PersistenceMetaDataDefaults
|
|||
*
|
||||
*/
|
||||
static class GetterFilter implements InclusiveFilter<Method> {
|
||||
|
||||
private boolean includePrivate;
|
||||
|
||||
public boolean includes(Method method) {
|
||||
return isGetter(method);
|
||||
return isGetter(method, isIncludePrivate());
|
||||
}
|
||||
|
||||
public void setIncludePrivate(boolean includePrivate) {
|
||||
this.includePrivate = includePrivate;
|
||||
}
|
||||
|
||||
public boolean isIncludePrivate() {
|
||||
return includePrivate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,7 @@ public class PersistenceProductDerivation
|
|||
Compatibility compatibility = conf.getCompatibilityInstance();
|
||||
compatibility.setFlushBeforeDetach(true);
|
||||
compatibility.setCopyOnDetach(true);
|
||||
compatibility.setPrivatePersistentProperties(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,28 @@
|
|||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section id="private_persistent_properties">
|
||||
<title>
|
||||
Use of private persistent properties
|
||||
</title>
|
||||
<para>
|
||||
In 1.x.x releases of OpenJPA, if property access was used,
|
||||
private properties were considered persistent. This is
|
||||
contrary to the JPA specification, which states that
|
||||
persistent properties must be public or protected. In
|
||||
OpenJPA 2.0 and later, private properties will not be
|
||||
persistent by default.
|
||||
</para>
|
||||
<para>
|
||||
It is possible to revert back to the 1.x.x behavior which
|
||||
allowed private properties to be persistent by setting the
|
||||
value of the <literal>openjpa.Compatibility</literal>
|
||||
property <literal>PrivatePersistentProperties</literal> to
|
||||
<literal>true</literal>. If compile time enhancement is
|
||||
used, this property must be specified at the time of
|
||||
enhancement and at runtime.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
Loading…
Reference in New Issue