001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo.externalizer;
012:
013: import com.versant.core.common.BindingSupportImpl;
014: import com.versant.core.common.Utils;
015:
016: import javax.jdo.PersistenceManager;
017: import java.lang.reflect.Constructor;
018: import java.lang.reflect.Method;
019: import java.io.Externalizable;
020: import java.io.ObjectInput;
021: import java.io.IOException;
022: import java.io.ObjectOutput;
023:
024: /**
025: * This externalizer can convert any type to/from String. The type must have
026: * a constructor that accepts a String. If it has a method 'String
027: * toExternalString()' then this is used to convert it to a String. Otherwise
028: * its toString() method is used.
029: *
030: * This class is Serializable. This is only a requirement if you are using
031: * remote PMs.
032: */
033: public class TypeAsStringExternalizer implements Externalizer,
034: Externalizable {
035:
036: public static final String SHORT_NAME = "STRING";
037:
038: private Class type;
039: private transient Constructor constructor;
040: private transient Method toExternalString;
041:
042: public TypeAsStringExternalizer(Class type) {
043: this .type = type;
044: init();
045: }
046:
047: public TypeAsStringExternalizer() {
048: }
049:
050: private void init() {
051: try {
052: constructor = type
053: .getConstructor(new Class[] { String.class });
054: } catch (NoSuchMethodException e) {
055: throw BindingSupportImpl.getInstance().runtime(
056: type + " does not have a "
057: + "constructor that accepts a String", e);
058: }
059: try {
060: toExternalString = type.getMethod("toExternalString", null);
061: if (toExternalString.getReturnType() != String.class) {
062: throw BindingSupportImpl.getInstance().runtime(
063: type + ".toExternalString() does not "
064: + "return String");
065: }
066: } catch (NoSuchMethodException e) {
067: // no problem - we will use toString
068: }
069: }
070:
071: public Object toExternalForm(PersistenceManager pm, Object o) {
072: if (o == null)
073: return null;
074: try {
075: return toExternalString == null ? o.toString()
076: : (String) toExternalString.invoke(o, null);
077: } catch (Throwable x) {
078: throw BindingSupportImpl.getInstance().runtime(
079: "Unable to convert instance of "
080: + type.getName()
081: + " using "
082: + (toExternalString == null ? "toString()"
083: : "toExternalString()") + ": " + x,
084: x);
085: }
086: }
087:
088: public Object fromExternalForm(PersistenceManager pm, Object o) {
089: if (o == null)
090: return null;
091: if (!(o instanceof String)) {
092: throw BindingSupportImpl.getInstance().runtime(
093: "Expected String to create instance of "
094: + type.getName() + ", got: "
095: + Utils.toString(o));
096: }
097: try {
098: return constructor.newInstance(new Object[] { o });
099: } catch (Throwable x) {
100: throw BindingSupportImpl.getInstance()
101: .fatalDatastore(
102: "Unable to create instance of "
103: + type.getName() + " from '"
104: + Utils.toString(o) + "': " + x, x);
105: }
106: }
107:
108: public Class getExternalType() {
109: return String.class;
110: }
111:
112: public void writeExternal(ObjectOutput out) throws IOException {
113: out.writeObject(type);
114: }
115:
116: public void readExternal(ObjectInput in) throws IOException,
117: ClassNotFoundException {
118: type = (Class) in.readObject();
119: init();
120: }
121: }
|