Using an NSArray or an NSMutableArray as a custom value class for an EOAttribute in an EOEntity with the conversion method "archiveData" causes the following exception when saving:
In WebObjects 4.0 - 4.5 there is an Objective-C category to NSObject that implemented the method "archiveData". This category is not available in WebObjects 5. To get the same function, you must create a subclass of NSMutableArray and add the conversion methods and user's implemention to that class. The example below shows how a custom class called CustomMutableArray is created which extends NSMutableArray and implements the archiving method "archiveData".
//
// CustomMutableArray.java
//
package com.mycompany.utilities;
import java.io.*;
import java.util.*;
import com.webobjects.foundation.*;
/**
* This class demonstrates how to create a custom value class.
* This particular class is a subclass of NSMutableArray which can be used
* within EOModeler.
*/
public class CustomMutableArray extends NSMutableArray {
/** This helps create the ByteArrayOutputStream with a good space estimate. */
private static final int kOverheadAdjustment = 512;
/** This also helps create the ByteArrayOutputStream with a good space estimate. */
private static final int kCountBytesFactor = 16;
/** This determines, when an error occurs, if we should throw an NSForwardException or just return null. */
private static final boolean kThrowOnError = true;
/**
* This is the factory method. Rename as appropriate from your EOModel.
* It uses java Serialization to turn bytes from an NSData into a reconstituted Object.
*
* @param data This is the NSData holding the previously serialized bytes.
* @return The un-serialized Object.
*/
public static Object objectWithArchiveData(NSData data) {
ByteArrayInputStream bis = new ByteArrayInputStream(data.bytes());
Object result = null;
Throwable exception = null;
try {
ObjectInputStream ois = new ObjectInputStream(bis);
result = ois.readObject();
} catch (IOException ioe) {
exception = ioe;
} catch (ClassNotFoundException cnfe) {
exception = cnfe;
}
if (exception != null) {
if
(NSLog.debugLoggingAllowedForLevelAndGroups(NSLog.DebugLevelCritical,
NSLog.DebugGroupArchiving)) {
NSLog.debug.appendln(exception);
}
if (kThrowOnError) {
throw new NSForwardException(exception);
}
}
return result;
}
/**
* This is the conversion method. Rename as appropriate from your EOModel.
* It uses java Serialization to serialize this object into bytes within an NSData.
*
* @return An NSData object containing the serialized bytes of this object.
*/
public NSData archiveData() {
ByteArrayOutputStream bos = new
ByteArrayOutputStream(kOverheadAdjustment + count() * kCountBytesFactor);
NSData result = null;
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
oos.close();
result = new NSData(bos.toByteArray());
} catch (IOException ioe) {
if
(NSLog.debugLoggingAllowedForLevelAndGroups(NSLog.DebugLevelCritical,
NSLog.DebugGroupArchiving)) {
NSLog.debug.appendln(ioe);
}
if (kThrowOnError) {
throw new NSForwardException(ioe);
}
}
return result;
}
}