All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebean.WithStaticFinder Maven / Gradle / Ivy

package io.ebean;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * Used to replace a "Finder" that is located as a static field (typically on an Model entity bean).
 * 

* This uses reflection to get/set the finder implementation with the ability to replace the original implementation * with the test double and restoring the original. */ public class WithStaticFinder { final Class beanType; String fieldName; Field field; Object original; Object testDouble; /** * Construct with a given bean type. */ public WithStaticFinder(Class beanType) { this.beanType = beanType; } /** * Construct with a given bean type. */ public WithStaticFinder(Class beanType, String fieldName) { this.beanType = beanType; this.fieldName = fieldName; } /** * Set the test double instance to use after useTestDouble() has been called. *

* Note that the test double instance is not set until useTestDouble() is called. */ public WithStaticFinder as(Object testDouble) throws FinderFieldNotFoundException { try { this.testDouble = testDouble; this.field = findField(); this.field.setAccessible(true); try { Field modifiersField = Field.class.getDeclaredField("modifiers"); /** * If the project using this library has a SecurityManager set up, permission may be denied. * Therefor, running this as a privileged action. */ AccessController.doPrivileged((PrivilegedAction) () -> { modifiersField.setAccessible(true); return null; }); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } this.original = field.get(null); return this; } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Set the test double to the field using reflection. *

* After this the test double will be used by calling code. */ public void useTestDouble() { try { this.field.set(null, testDouble); } catch (IllegalAccessException e) { throw new FinderIllegalAccessException(e); } } /** * Restore the original implementation using reflection. */ public void restoreOriginal() { try { this.field.set(null, original); } catch (IllegalAccessException e) { throw new FinderIllegalAccessException(e); } } /** * Find and return the "find" field. */ protected Field findField() throws FinderFieldNotFoundException { try { if (fieldName != null) { return beanType.getField(fieldName); } try { return beanType.getField("find"); } catch (NoSuchFieldException e) { return beanType.getField("FIND"); } } catch (NoSuchFieldException e) { throw new FinderFieldNotFoundException(e); } } /** * Set the given test double onto the given class returning the WithStaticFinder. *

* Use restore to put the original finder back onto the class. *

* *
{@code
   *
   *   // Replace the finder with TDCustFinder
   *   WithStaticFinder with = WithStaticFinder.use(Customer.class, new TDCustFinder());
   *   try {
   *     // perform some test
   *     Customer jim = Customer.find.byName("jim");
   *
   *   } finally {
   *     // restore the original finder
   *     with.restoreOriginal();
   *   }
   *
   * }
*/ public static WithStaticFinder use(Class cls, Object testFinder) { WithStaticFinder with = new WithStaticFinder<>(cls); with.as(testFinder); with.useTestDouble(); return with; } }