The approach I found worked the best:
1. Copy the string into a pre-allocated and re-used char[] array. This
is needed since the JDK does not permit access to the String's
char[] ,to enforce immutability. This is a performance "loss" VS the
JDK, which can access the char[] directly....
Evan,
you may access a String's internals via reflection in a "safe," albeit
potentially implementation-specific way. See class code below.
As long as your java.lang.String uses "value" for the char[] and
"offset" for the storage offset, this should work.
No sun.misc.Unsafe used. Only tested/used on JDK6.
David
/***************************************************************************
**********/
import java.lang.reflect.*;
public final class ReflectionUtils {
/**
* There is no explicit Modifier constant for package-privete, so 0 is
used.
*/
public static final int MODIFIER_PACKAGE_PRIVATE = 0x00000000;
/** Field object for accessing Sting::value character storage. */
public static final Field STRING_VALUE_FIELD =
getFieldAccessible(String.class, "value");
/** Field object for accessing Sting::offset, the first index used in
the value[] char storage. */
public static final Field STRING_OFFSET_FIELD =
getFieldAccessible(String.class, "offset");
/**
* Package private String constructor which shares value array for
speed.
*
* Use when a number of String objects share the same char[] storage.
*
* See String(int offset, int count, char value[]).
*/
public static final Constructor<?> STRING_PP_CTOR =
getConstructor(String.class, MODIFIER_PACKAGE_PRIVATE, int.class, int.class,
char[].class);
/**
* To avoid violating final field semantics, take care to only _read_
* the char[] value returned.
*/
public static char[] getChars(final String s) {
try {
// use reflection to read the char[] value from the string. . .
return (char[]) STRING_VALUE_FIELD.get(s);
} catch (Throwable t) {
return null;
}
}
public static String sharedString(final char[] chars, final int offset,
final int length) {
try {
return (String) STRING_PP_CTOR.newInstance(offset, length,
chars);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
public static Field getFieldAccessible(final Class<?> clazz, final
String fieldName) {
Field fld = null;
try {
fld = clazz.getDeclaredField(fieldName);
fld.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return fld;
}
public static Constructor<?> getConstructor(final Class<?> clazz, final
int searchModifier, final Class<?>... paramTypes) {
if(clazz==null) {
throw new IllegalArgumentException("A class parameter is
required");
}
try {
//
// There is no explicit Modifier accessor constant for
package-privete, so 0 is used.
//
for (Constructor<?> ctor : clazz.getDeclaredConstructors()) {
if (searchModifier == (ctor.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED))) {
//
// access modifier matches. . .
//
final Class<?>[] parameterTypes =
ctor.getParameterTypes();
if (parameterTypes.length == paramTypes.length) {
//
// same number of parameters. . .
//
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].equals(paramTypes[i])) {
// one parameter not of correct type, so
bail. . .
// note ctor variable used as success marker
below
ctor = null;
break;
} else {
// Type[] gpType =
ctor.getGenericParameterTypes();
// for (int j = 0; j < gpType.length; j++) {
// char ch =
(gpType[j].equals(paramTypes[i]) ? '*' : ' ');
// System.out.format("%7c%s[%d]: %s%n",
ch, "GenericParameterType", j, gpType[j]);
// }
}
}
if (ctor != null) {
// all ctor parameter types match, so call
ctor.setAccessible(true)
// System.out.format("%s%n",
ctor.toGenericString());
// System.out.format(" [ synthetic=%-5b
var_args=%-5b ]%n", ctor.isSynthetic(), ctor.isVarArgs());
ctor.setAccessible(true);
return ctor;
}
}
}
}
} catch (Throwable t) {
// will return null below
}
return null; // error or ctor not found
}
/**
* The AccessibleObject class is the base class for Field, Method and
* Constructor objects. It provides the ability to flag a reflected
* object as suppressing default Java language access control checks
* when it is used. The access checks--for public, default (package)
* access, protected, and private members--are performed when Fields,
* Methods or Constructors are used to set or get fields, to invoke
* methods, or to create and initialize new instances of classes,
* respectively.
*
* <p>Setting the <tt>accessible</tt> flag in a reflected object
* permits sophisticated applications with sufficient privilege, such
* as Java Object Serialization or other persistence mechanisms, to
* manipulate objects in a manner that would normally be prohibited.
*
* @see AccessibleObject
*
**/
public static boolean setAccessible(final AccessibleObject o) {
try {
o.setAccessible(true);
return true;
} catch (Throwable /*SecurityException*/ e) {
return false;
}
}
}
--
You received this message because you are subscribed to the Google Groups
"Protocol Buffers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/protobuf?hl=en.