vendredi 28 juillet 2017

Access level aware dependency injection into inherited field

At work there is a process framework. It uses keys and containers to set parameters without the use of dedicated constructors (it's basically the type safe heterogeneous container pattern).

I recently added dependency injection. Below you find an example (it lacks some null checks, access control, etc.)

  private static void inject(Process instance, Container c) throws Exception
  {
    Class<?> reference = instance.getClass();
    for (Field field : reference.getDeclaredFields())
    {
      Inject inject = field.getAnnotation(Inject.class);

      Key<Object> key = new Key<>(inject.key());
      field.set(instance, c.getObject(key));
    }
  }

The implementation is working, but know I need to enhance it in order to also inject into inherited fields.

I had no problem retrieving the type hierachy and all the annotated, inherited fields. But in order to comply with Java, I must not inject into every retrieved field.

Only when the field is:

  1. public
  2. protected
  3. package-privated and declared in a class that has the same package as reference
  4. private and declared in a non-static class that is enclosed by reference

Items 1 - 3 are easy to check for. I have difficulties with the last item. Is there an elegant solution?

I thougt about using java.lang.Class.isMemberClass() and comparing class names.

Currently my check looks like this

  private static boolean accessAllowed(Class<?> reference, Field field)
  {
    int modifiers = field.getModifiers();

    boolean hasAccess = Modifier.isPublic(modifiers);
    hasAccess |= Modifier.isProtected(modifiers);

    // TODO fix
    hasAccess |= Modifier.isPrivate(modifiers) /* add check */;

    // no access and not private means field is package-private
    if (!hasAccess && !Modifier.isPrivate(modifiers))
      hasAccess = reference.getPackage().equals(field.getDeclaringClass().getPackage());

    return hasAccess;
  }

Is there an easy and/or efficient way to find out whether a class is enclosed by another class? Or is there another way to find out whether I am allowed to inject?





Aucun commentaire:

Enregistrer un commentaire