Added iBatis support for java.io.Serializable

- 'alf_prop_serializable_value' is working


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15993 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-08-29 00:47:25 +00:00
parent 7fbccecd71
commit 200bf8d3a0
10 changed files with 355 additions and 13 deletions

View File

@@ -52,6 +52,7 @@
<property name="propertyDateValueCache" ref="immutableEntityCache"/>
<property name="propertyStringValueCache" ref="immutableEntityCache"/>
<property name="propertyDoubleValueCache" ref="immutableEntityCache"/>
<property name="propertySerializableValueCache" ref="immutableEntityCache"/>
<property name="propertyValueCache" ref="immutableEntityCache"/>
</bean>

View File

@@ -15,6 +15,7 @@
<typeAlias alias="PropertyStringValue" type="org.alfresco.repo.domain.propval.PropertyStringValueEntity"/>
<typeAlias alias="PropertyStringQuery" type="org.alfresco.repo.domain.propval.PropertyStringQueryEntity"/>
<typeAlias alias="PropertyDoubleValue" type="org.alfresco.repo.domain.propval.PropertyDoubleValueEntity"/>
<typeAlias alias="PropertySerializableValue" type="org.alfresco.repo.domain.propval.PropertySerializableValueEntity"/>
<typeAlias alias="PropertyValue" type="org.alfresco.repo.domain.propval.PropertyValueEntity"/>
<typeAlias alias="PropertyLink" type="org.alfresco.repo.domain.propval.PropertyLinkEntity"/>
<typeAlias alias="PropertyIdSearchRow" type="org.alfresco.repo.domain.propval.PropertyIdSearchRow"/>
@@ -52,6 +53,10 @@
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="doubleValue" column="double_value" jdbcType="DOUBLE" javaType="java.lang.Double"/>
</resultMap>
<resultMap id="result.PropertySerializableValue" class="PropertySerializableValue">
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="serializableValue" column="serializable_value" jdbcType="BLOB" javaType="java.io.Serializable"/>
</resultMap>
<resultMap id="result.PropertyValue" class="PropertyValue">
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="actualTypeId" column="actual_type_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
@@ -59,7 +64,7 @@
<result property="longValue" column="long_value" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="doubleValue" column="double_value" jdbcType="DOUBLE" javaType="java.lang.Double"/>
<result property="stringValue" column="string_value" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="serializableValue" column="serializable_value" jdbcType="BLOB" javaType="java.lang.Object"/>
<result property="serializableValue" column="serializable_value" jdbcType="BLOB" javaType="java.io.Serializable"/>
</resultMap>
<resultMap id="result.PropertyLink" class="PropertyLink">
<result property="rootPropId" column="root_prop_id" jdbcType="BIGINT" javaType="long"/>
@@ -77,13 +82,17 @@
<result property="longValue" column="long_value" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="doubleValue" column="double_value" jdbcType="DOUBLE" javaType="java.lang.Double"/>
<result property="stringValue" column="string_value" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="serializableValue" column="serializable_value" jdbcType="BLOB" javaType="java.lang.Object"/>
<result property="serializableValue" column="serializable_value" jdbcType="BLOB" javaType="java.io.Serializable"/>
</resultMap>
<!-- -->
<!-- Parameter Maps -->
<!-- -->
<parameterMap id="parameter.PropertySerializableValue" class="PropertySerializableValue">
<parameter property="serializableValue" jdbcType="BLOB" javaType="java.io.Serializable"/>
</parameterMap>
<!-- -->
<!-- SQL Snippets -->
<!-- -->
@@ -103,6 +112,11 @@
values (#doubleValue#)
</sql>
<sql id="insert.PropertySerializableValue.AutoIncrement">
insert into alf_prop_serializable_value (serializable_value)
values (?)
</sql>
<sql id="insert.PropertyValue.AutoIncrement">
insert into alf_prop_value (actual_type_id, persisted_type, long_value)
values (#actualTypeId#, #persistedType#, #longValue#)
@@ -214,6 +228,16 @@
double_value = #doubleValue#
</select>
<!-- Get a property serializable value by ID -->
<select id="select.PropertySerializableValueByID" parameterClass="PropertySerializableValue" resultMap="result.PropertySerializableValue">
select
*
from
alf_prop_serializable_value
where
id = #id#
</select>
<!-- Get the property value by value in alf_prop_value -->
<select id="select.PropertyValueByLocalValue" parameterClass="PropertyValue" resultMap="result.PropertyValue">
select

View File

@@ -27,6 +27,13 @@
</selectKey>
</insert>
<insert id="insert.PropertySerializableValue" parameterMap="parameter.PropertySerializableValue" >
<include refid="insert.PropertySerializableValue.AutoIncrement"/>
<selectKey resultClass="long" keyProperty="id" type="post">
KEY_COLUMN:GENERATED_KEY
</selectKey>
</insert>
<insert id="insert.PropertyValue" parameterClass="PropertyValue" >
<include refid="insert.PropertyValue.AutoIncrement"/>
<selectKey resultClass="long" keyProperty="id" type="post">

View File

@@ -6,6 +6,8 @@
<sqlMapConfig>
<typeHandler javaType="java.io.Serializable" jdbcType="BLOB" callback="org.alfresco.ibatis.SerializableTypeHandlerCallback"/>
<sqlMap resource="alfresco/ibatis/#resource.dialect#/propval-common-SqlMap.xml"/>
<sqlMap resource="alfresco/ibatis/#resource.dialect#/propval-insert-SqlMap.xml"/>

View File

@@ -168,6 +168,26 @@ public class EntityLookupCache<K extends Serializable, V extends Object, VK exte
public static abstract class EntityLookupCallbackDAOAdaptor<K2 extends Serializable, V2 extends Object, VK2 extends Serializable>
implements EntityLookupCallbackDAO<K2, V2, VK2>
{
/**
* This implementation never finds a value and is backed by {@link #getValueKey(Object)} returning nothing.
*
* @return Returns <tt>null</tt> always
*/
public Pair<K2, V2> findByValue(V2 value)
{
return null;
}
/**
* This implementation does not find by value and is backed by {@link #findByValue(Object)} returning nothing.
*
* @return Returns <tt>null</tt> always
*/
public VK2 getValueKey(V2 value)
{
return null;
}
/**
* Disallows the operation.
*

View File

@@ -60,6 +60,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
private static final String CACHE_REGION_PROPERTY_DATE_VALUE = "PropertyDateValue";
private static final String CACHE_REGION_PROPERTY_STRING_VALUE = "PropertyStringValue";
private static final String CACHE_REGION_PROPERTY_DOUBLE_VALUE = "PropertyDoubleValue";
private static final String CACHE_REGION_PROPERTY_SERIALIZABLE_VALUE = "PropertySerializableValue";
private static final String CACHE_REGION_PROPERTY_VALUE = "PropertyValue";
private static final Log logger = LogFactory.getLog(AbstractPropertyValueDAOImpl.class);
@@ -70,6 +71,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
private final PropertyDateValueCallbackDAO propertyDateValueCallback;
private final PropertyStringValueCallbackDAO propertyStringValueCallback;
private final PropertyDoubleValueCallbackDAO propertyDoubleValueCallback;
private final PropertySerializableValueCallbackDAO propertySerializableValueCallback;
private final PropertyValueCallbackDAO propertyValueCallback;
/**
* Cache for the property class:<br/>
@@ -99,6 +101,13 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
* VALUE KEY: The value itself<br/>
*/
private EntityLookupCache<Long, Double, Double> propertyDoubleValueCache;
/**
* Cache for the property Serializable value:<br/>
* KEY: ID<br/>
* VALUE: The Serializable instance<br/>
* VALUE KEY: none<br/>. The cache is not used for value-based lookups.
*/
private EntityLookupCache<Long, Serializable, Serializable> propertySerializableValueCache;
/**
* Cache for the property value:<br/>
* KEY: ID<br/>
@@ -119,12 +128,14 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
this.propertyDateValueCallback = new PropertyDateValueCallbackDAO();
this.propertyStringValueCallback = new PropertyStringValueCallbackDAO();
this.propertyDoubleValueCallback = new PropertyDoubleValueCallbackDAO();
this.propertySerializableValueCallback = new PropertySerializableValueCallbackDAO();
this.propertyValueCallback = new PropertyValueCallbackDAO();
this.propertyClassCache = new EntityLookupCache<Long, Class<?>, String>(propertyClassDaoCallback);
this.propertyDateValueCache = new EntityLookupCache<Long, Date, Date>(propertyDateValueCallback);
this.propertyStringValueCache = new EntityLookupCache<Long, String, Pair<String, Long>>(propertyStringValueCallback);
this.propertyDoubleValueCache = new EntityLookupCache<Long, Double, Double>(propertyDoubleValueCallback);
this.propertySerializableValueCache = new EntityLookupCache<Long, Serializable, Serializable>(propertySerializableValueCallback);
this.propertyValueCache = new EntityLookupCache<Long, Serializable, Serializable>(propertyValueCallback);
}
@@ -188,6 +199,19 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
propertyDoubleValueCallback);
}
/**
* Set the cache to use for <b>alf_prop_serializable_value</b> lookups (optional).
*
* @param propertySerializableValueCache the cache of IDs to property values
*/
public void setPropertySerializableValueCache(SimpleCache<Serializable, Object> propertySerializableValueCache)
{
this.propertySerializableValueCache = new EntityLookupCache<Long, Serializable, Serializable>(
propertySerializableValueCache,
CACHE_REGION_PROPERTY_SERIALIZABLE_VALUE,
propertySerializableValueCallback);
}
/**
* Set the cache to use for <b>alf_prop_value</b> lookups (optional).
*
@@ -548,6 +572,67 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO
protected abstract PropertyDoubleValueEntity findDoubleValueByValue(Double value);
protected abstract PropertyDoubleValueEntity createDoubleValue(Double value);
//================================
// 'alf_prop_serializable_value' accessors
//================================
public Pair<Long, Serializable> getPropertySerializableValueById(Long id)
{
if (id == null)
{
throw new IllegalArgumentException("Cannot look up entity by null ID.");
}
Pair<Long, Serializable> entityPair = propertySerializableValueCache.getByKey(id);
if (entityPair == null)
{
throw new AlfrescoRuntimeException("No property serializable value exists for ID " + id);
}
return entityPair;
}
public Pair<Long, Serializable> createPropertySerializableValue(Serializable value)
{
if (value == null)
{
throw new IllegalArgumentException("Persisted serializable values cannot be null");
}
Pair<Long, Serializable> entityPair = propertySerializableValueCache.getOrCreateByValue(value);
return (Pair<Long, Serializable>) entityPair;
}
/**
* Callback for <b>alf_prop_serializable_value</b> DAO.
*/
private class PropertySerializableValueCallbackDAO extends EntityLookupCallbackDAOAdaptor<Long, Serializable, Serializable>
{
private final Pair<Long, Serializable> convertEntityToPair(PropertySerializableValueEntity entity)
{
if (entity == null)
{
return null;
}
else
{
return entity.getEntityPair();
}
}
public Pair<Long, Serializable> createValue(Serializable value)
{
PropertySerializableValueEntity entity = createSerializableValue(value);
return convertEntityToPair(entity);
}
public Pair<Long, Serializable> findByKey(Long key)
{
PropertySerializableValueEntity entity = findSerializableValueById(key);
return convertEntityToPair(entity);
}
}
protected abstract PropertySerializableValueEntity findSerializableValueById(Long id);
protected abstract PropertySerializableValueEntity createSerializableValue(Serializable value);
//================================
// 'alf_prop_value' accessors
//================================

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.domain.propval;
import java.io.Serializable;
import org.alfresco.util.Pair;
/**
* Entity bean for <b>alf_prop_serializable_value</b> table.
*
* @author Derek Hulley
* @since 3.2
*/
public class PropertySerializableValueEntity
{
private Long id;
private Serializable serializableValue;
public PropertySerializableValueEntity()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(512);
sb.append("PropertySerializableValueEntity")
.append("[ id=").append(id)
.append(", value=").append(serializableValue)
.append("]");
return sb.toString();
}
/**
* @return Returns the ID-value pair
*/
public Pair<Long, Serializable> getEntityPair()
{
return new Pair<Long, Serializable>(id, serializableValue);
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Serializable getSerializableValue()
{
return serializableValue;
}
public void setSerializableValue(Serializable serializableValue)
{
this.serializableValue = serializableValue;
}
}

View File

@@ -125,6 +125,22 @@ public interface PropertyValueDAO
*/
Pair<Long, Double> getOrCreatePropertyDoubleValue(Double value);
//================================
// 'alf_prop_serializable_value' accessors
//================================
/**
* <b>alf_prop_serializable_value</b> accessor
*
* @param id the ID (may not be <tt>null</tt>)
*/
Pair<Long, Serializable> getPropertySerializableValueById(Long id);
/**
* <b>alf_prop_serializable_value</b> accessor
*
* @param value the value to find the ID for (may not be <tt>null</tt>)
*/
Pair<Long, Serializable> createPropertySerializableValue(Serializable value);
//================================
// 'alf_prop_value' accessors
//================================

View File

@@ -31,6 +31,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.naming.CompositeName;
import junit.framework.TestCase;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
@@ -40,6 +42,7 @@ import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.util.Pair;
import org.bouncycastle.util.Arrays;
import org.springframework.context.ApplicationContext;
/**
@@ -147,7 +150,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, Date> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getOrCreatePropertyDateValue(dateValue);
}
};
@@ -159,7 +161,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, Date> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getPropertyDateValue(dateValue);
}
};
@@ -177,7 +178,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, String> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getOrCreatePropertyStringValue(stringValue);
}
};
@@ -207,7 +207,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, String> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getOrCreatePropertyStringValue(stringValueUpper);
}
};
@@ -241,7 +240,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, Double> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getOrCreatePropertyDoubleValue(doubleValue);
}
};
@@ -253,7 +251,6 @@ public class PropertyValueDAOTest extends TestCase
{
public Pair<Long, Double> execute() throws Throwable
{
// Get the classes
return propertyValueDAO.getPropertyDoubleValue(doubleValue);
}
};
@@ -262,6 +259,49 @@ public class PropertyValueDAOTest extends TestCase
assertEquals(entityPair, entityPairCheck);
}
public void testPropertySerializableValue() throws Exception
{
final Serializable serializableValue = new CompositeName("123");
RetryingTransactionCallback<Pair<Long, Serializable>> createValueCallback = new RetryingTransactionCallback<Pair<Long, Serializable>>()
{
public Pair<Long, Serializable> execute() throws Throwable
{
return propertyValueDAO.createPropertySerializableValue(serializableValue);
}
};
final Pair<Long, Serializable> entityPair = txnHelper.doInTransaction(createValueCallback, false);
assertNotNull(entityPair);
assertEquals(serializableValue, entityPair.getSecond());
RetryingTransactionCallback<Pair<Long, Serializable>> getValueCallback = new RetryingTransactionCallback<Pair<Long, Serializable>>()
{
public Pair<Long, Serializable> execute() throws Throwable
{
return propertyValueDAO.getPropertySerializableValueById(entityPair.getFirst());
}
};
final Pair<Long, Serializable> entityPairCheck = txnHelper.doInTransaction(getValueCallback, false);
assertNotNull(entityPairCheck);
assertEquals(entityPair.getFirst(), entityPairCheck.getFirst());
assertEquals(entityPair, entityPairCheck);
// Check that we can persist and retrieve byte[] as a Serializable
final Serializable bytes = (Serializable) new byte[] {1, 2, 3};
RetryingTransactionCallback<Pair<Long, Void>> testBytesCallback = new RetryingTransactionCallback<Pair<Long, Void>>()
{
public Pair<Long, Void> execute() throws Throwable
{
Long id = propertyValueDAO.createPropertySerializableValue(bytes).getFirst();
Serializable check = propertyValueDAO.getPropertySerializableValueById(id).getSecond();
assertNotNull(check);
assertTrue(check instanceof byte[]);
Arrays.areEqual((byte[])bytes, (byte[])check);
return null;
}
};
txnHelper.doInTransaction(testBytesCallback, false);
}
/**
* Tests that the given value can be persisted and retrieved with the same resulting ID
*/
@@ -371,7 +411,7 @@ public class PropertyValueDAOTest extends TestCase
public void testPropertyValue_Date() throws Exception
{
Random rand = new Random();
for (long i = 0; i < 1000; i++)
for (long i = 0; i < 100; i++)
{
runPropertyValueTest(new Date(rand.nextLong()));
}
@@ -385,6 +425,15 @@ public class PropertyValueDAOTest extends TestCase
}
}
public void testPropertyValue_Serializable() throws Exception
{
for (int i = 0; i < 100; i++)
{
// Choose a type that implements equals and hashCode but will not be recognised
runPropertyValueTest(new CompositeName("Name-"+i), false);
}
}
public void testPropertyValue_MapOfStrings() throws Exception
{
final HashMap<String, String> map = new HashMap<String, String>(15);
@@ -397,6 +446,24 @@ public class PropertyValueDAOTest extends TestCase
runPropertyValueTest(map, false);
}
public void testPropertyValue_MapOfMapOfSerializables() throws Exception
{
final HashMap<String, Serializable> mapInner = new HashMap<String, Serializable>(15);
for (int i = 0; i < 20; i++)
{
String key = "INNERMAP-KEY-" + i;
Serializable value = new CompositeName("INNERMAP-VALUE-" + i);
mapInner.put(key, value);
}
final HashMap<String, Map<?, ?>> mapOuter = new HashMap<String, Map<?, ?>>(37);
for (int i = 0; i < 2; i++)
{
String key = "OUTERMAP-KEY-" + i;
mapOuter.put(key, mapInner);
}
runPropertyValueTest(mapOuter, false);
}
public void testPropertyValue_MapOfMapOfStrings() throws Exception
{
final HashMap<String, String> mapInner = new HashMap<String, String>(15);
@@ -449,4 +516,10 @@ public class PropertyValueDAOTest extends TestCase
removeCaches();
testPropertyDoubleValue();
}
public void testPropertySerializableValue_NoCache() throws Exception
{
removeCaches();
testPropertySerializableValue();
}
}

View File

@@ -34,6 +34,7 @@ import org.alfresco.repo.domain.propval.PropertyDateValueEntity;
import org.alfresco.repo.domain.propval.PropertyDoubleValueEntity;
import org.alfresco.repo.domain.propval.PropertyIdSearchRow;
import org.alfresco.repo.domain.propval.PropertyLinkEntity;
import org.alfresco.repo.domain.propval.PropertySerializableValueEntity;
import org.alfresco.repo.domain.propval.PropertyStringQueryEntity;
import org.alfresco.repo.domain.propval.PropertyStringValueEntity;
import org.alfresco.repo.domain.propval.PropertyValueEntity;
@@ -65,6 +66,9 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl
private static final String SELECT_PROPERTY_DOUBLE_VALUE_BY_VALUE = "select.PropertyDoubleValueByValue";
private static final String INSERT_PROPERTY_DOUBLE_VALUE = "insert.PropertyDoubleValue";
private static final String SELECT_PROPERTY_SERIALIZABLE_VALUE_BY_ID = "select.PropertySerializableValueByID";
private static final String INSERT_PROPERTY_SERIALIZABLE_VALUE = "insert.PropertySerializableValue";
private static final String SELECT_PROPERTY_VALUE_BY_ID = "select.PropertyValueById";
private static final String SELECT_PROPERTY_VALUE_BY_LOCAL_VALUE = "select.PropertyValueByLocalValue";
private static final String SELECT_PROPERTY_VALUE_BY_DOUBLE_VALUE = "select.PropertyValueByDoubleValue";
@@ -250,6 +254,33 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl
return entity;
}
//================================
// 'alf_prop_serializable_value' accessors
//================================
@Override
protected PropertySerializableValueEntity findSerializableValueById(Long id)
{
PropertySerializableValueEntity entity = new PropertySerializableValueEntity();
entity.setId(id);
entity = (PropertySerializableValueEntity) template.queryForObject(
SELECT_PROPERTY_SERIALIZABLE_VALUE_BY_ID,
entity);
// Done
return entity;
}
@Override
protected PropertySerializableValueEntity createSerializableValue(Serializable value)
{
PropertySerializableValueEntity entity = new PropertySerializableValueEntity();
entity.setSerializableValue(value);
Long id = (Long) template.insert(INSERT_PROPERTY_SERIALIZABLE_VALUE, entity);
entity.setId(id);
// Done
return entity;
}
//================================
// 'alf_prop_value' accessors
//================================
@@ -367,10 +398,9 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl
insertEntity.setLongValue(insertStringPair.getFirst());
break;
case SERIALIZABLE:
throw new UnsupportedOperationException("Serializable not supported, yet.");
// Pair<Long, Serializable> insertSerializablePair = getOrCreatePropertySerializableValue(value);
// insertEntity.setLongValue(insertSerializablePair.getFirst());
// break;
Pair<Long, Serializable> insertSerializablePair = createPropertySerializableValue(value);
insertEntity.setLongValue(insertSerializablePair.getFirst());
break;
case NULL:
case LONG:
// Do nothing for these