Enforce restrictions on the model behavior class statically

If a client violates these restrictions, I prefer that their code fail
at compile time instead of run time.  Changing a few key types from
`Class` to `Class<? extends AbstractAndroidModel>` gives us precisely
the static enforcement we need and lets us remove an
`AbstractAndroidModel.class.isAssignableFrom` run-time check.

However, this does change the public API of `AndroidEntryPointManager`
in two ways.  The `getModelBehavior` and `setModelBehavior` methods now
respectively accept and return `Class<?  extends AbstractAndroidModel>`
instead of `Class`.  Is tightening up a public API in this manner
considered OK?
This commit is contained in:
Ben Liblit 2016-11-06 12:12:46 -06:00
parent 4080e49a5a
commit b3293ecc3e

View File

@ -252,7 +252,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return prev;
}
private Class abstractAndroidModel = LoopAndroidModel.class;
private Class<? extends AbstractAndroidModel> abstractAndroidModel = LoopAndroidModel.class;
/**
* What special handling to insert into the model.
*
@ -271,13 +271,13 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return new LoopAndroidModel(body, insts, paramManager, entryPoints);
} else {
try {
final Constructor<AbstractAndroidModel> ctor = this.abstractAndroidModel.getDeclaredConstructor(
final Constructor<? extends AbstractAndroidModel> ctor = this.abstractAndroidModel.getDeclaredConstructor(
VolatileMethodSummary.class, TypeSafeInstructionFactory.class, SSAValueManager.class,
Iterable.class);
if (ctor == null) {
throw new IllegalStateException("Canot find the constructor of " + this.abstractAndroidModel);
}
return (AbstractAndroidModel) ctor.newInstance(body, insts, paramManager, entryPoints);
return ctor.newInstance(body, insts, paramManager, entryPoints);
} catch (java.lang.InstantiationException e) {
throw new IllegalStateException(e);
} catch (java.lang.IllegalAccessException e) {
@ -300,24 +300,20 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
*
* @return null or the class set using setModelBehavior
*/
public Class getModelBehavior() {
public Class<? extends AbstractAndroidModel> getModelBehavior() {
return this.abstractAndroidModel;
}
/**
* Set the class instantiated by makeModelBehavior.
*
* @throws IllgealArgumentException if the abstractAndroidModel does not subclass AbstractAndroidModel
* @throws IllegalArgumentException if the abstractAndroidModel is null
*/
public void setModelBehavior(Class abstractAndroidModel) {
public void setModelBehavior(Class<? extends AbstractAndroidModel> abstractAndroidModel) {
if (abstractAndroidModel == null) {
throw new IllegalArgumentException("abstractAndroidModel may not be null. Use SequentialAndroidModel " +
"if no special handling shall be inserted.");
}
if (! AbstractAndroidModel.class.isAssignableFrom(abstractAndroidModel)) {
throw new IllegalArgumentException("The given argument abstractAndroidModel does not subclass " +
"AbtractAndroidModel");
}
this.abstractAndroidModel = abstractAndroidModel;
}