/** * Attempt to create a safe clone of the given key object. * This algorithm first checks to see if the key's class implements {@link Destroyable}; if not, it is returned as-is. * Next it checks to see if the key has been destroyed; if so, it is returned as-is. * Next it determines if the key actually implements the {@link Destroyable} interface; if not, it is returned as-is. * Then it determines if there is a public {@code clone} method that returns a compatible type; if so, that method is used. * Then it determines if the key implements a known key interface; if so, a raw implementation of that interface is produced. * Last it checks to see if the key is some other unknown {@link SecretKey} type; if so, it captures its value using a {@link SecretKeySpec}. * If none of these checks succeed, an exception is thrown. * * @param expectType the expected result type (must not be {@code null}) * @param key the key object * @return the cloned key, or the original if the key type is not destroyable */ public static <T extends Key> T cloneKey(Class<T> expectType, T key) { Assert.checkNotNullParam("expectType", expectType); if (key instanceof Destroyable) { // medium path if (((Destroyable) key).isDestroyed()) { return expectType.cast(key); } else { return expectType.cast(CLONER_CREATOR.get(key.getClass()).apply(key)); } } else { // fast path return expectType.cast(key); } }
/** * Attempt to create a safe clone of the given key object. * This algorithm first checks to see if the key's class implements {@link Destroyable}; if not, it is returned as-is. * Next it checks to see if the key has been destroyed; if so, it is returned as-is. * Next it determines if the key actually implements the {@link Destroyable} interface; if not, it is returned as-is. * Then it determines if there is a public {@code clone} method that returns a compatible type; if so, that method is used. * Then it determines if the key implements a known key interface; if so, a raw implementation of that interface is produced. * Last it checks to see if the key is some other unknown {@link SecretKey} type; if so, it captures its value using a {@link SecretKeySpec}. * If none of these checks succeed, an exception is thrown. * * @param expectType the expected result type (must not be {@code null}) * @param key the key object * @return the cloned key, or the original if the key type is not destroyable */ public static <T extends Key> T cloneKey(Class<T> expectType, T key) { Assert.checkNotNullParam("expectType", expectType); if (key instanceof Destroyable) { // medium path if (((Destroyable) key).isDestroyed()) { return expectType.cast(key); } else { return expectType.cast(CLONER_CREATOR.get(key.getClass()).apply(key)); } } else { // fast path return expectType.cast(key); } }
/** * Attempt to create a safe clone of the given key object. * This algorithm first checks to see if the key's class implements {@link Destroyable}; if not, it is returned as-is. * Next it checks to see if the key has been destroyed; if so, it is returned as-is. * Next it determines if the key actually implements the {@link Destroyable} interface; if not, it is returned as-is. * Then it determines if there is a public {@code clone} method that returns a compatible type; if so, that method is used. * Then it determines if the key implements a known key interface; if so, a raw implementation of that interface is produced. * Last it checks to see if the key is some other unknown {@link SecretKey} type; if so, it captures its value using a {@link SecretKeySpec}. * If none of these checks succeed, an exception is thrown. * * @param expectType the expected result type (must not be {@code null}) * @param key the key object * @return the cloned key, or the original if the key type is not destroyable */ public static <T extends Key> T cloneKey(Class<T> expectType, T key) { Assert.checkNotNullParam("expectType", expectType); if (key instanceof Destroyable) { // medium path if (((Destroyable) key).isDestroyed()) { return expectType.cast(key); } else { return expectType.cast(CLONER_CREATOR.get(key.getClass()).apply(key)); } } else { // fast path return expectType.cast(key); } }
/** * Attempt to create a safe clone of the given key object. * This algorithm first checks to see if the key's class implements {@link Destroyable}; if not, it is returned as-is. * Next it checks to see if the key has been destroyed; if so, it is returned as-is. * Next it determines if the key actually implements the {@link Destroyable} interface; if not, it is returned as-is. * Then it determines if there is a public {@code clone} method that returns a compatible type; if so, that method is used. * Then it determines if the key implements a known key interface; if so, a raw implementation of that interface is produced. * Last it checks to see if the key is some other unknown {@link SecretKey} type; if so, it captures its value using a {@link SecretKeySpec}. * If none of these checks succeed, an exception is thrown. * * @param expectType the expected result type (must not be {@code null}) * @param key the key object * @return the cloned key, or the original if the key type is not destroyable */ public static <T extends Key> T cloneKey(Class<T> expectType, T key) { Assert.checkNotNullParam("expectType", expectType); if (key instanceof Destroyable) { // medium path if (((Destroyable) key).isDestroyed()) { return expectType.cast(key); } else { return expectType.cast(CLONER_CREATOR.get(key.getClass()).apply(key)); } } else { // fast path return expectType.cast(key); } }