Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do app servers inject into private fields?

I saw this question

Inject into private, package or public field or provide a setter?

about how to manually inject into annotated private fields (The way is adding setters or through a constructor)

But, the point is how do an application server (like glassfish, axis2, jboss, ...) is able to inject into a final private field (without adding setters or constructors to the user class)?

Quoting the cited question:

public SomeClass {
  @Inject
  private SomeResource resource;
}

Do they use a customized JVM (not the standard one) that allows to access private fields?

Thanks

like image 713
cibercitizen1 Avatar asked Apr 05 '10 15:04

cibercitizen1


People also ask

What is dependency injection and how does it work?

Dependency Injection (DI) is a design pattern used to implement IoC. It allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them.

Which of the following are methods of dependency injection?

There are three types of dependency injection — constructor injection, method injection, and property injection.

How does Java dependency injection work?

Dependency injection enables you to turn regular Java classes into managed objects and to inject them into any other managed object. Using dependency injection, your code can declare dependencies on any managed object.

What is the use of @inject annotation?

Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class. @Inject is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.


2 Answers

It's a simple reflection "trick". It relies on the Field.setAccessible() method to force the member to be accessible programmatically:

Set the accessible flag for this object to the indicated boolean value. A value of true indicates that the reflected object should suppress Java language access checking when it is used. A value of false indicates that the reflected object should enforce Java language access checks.

The Reflection API is used to get a handle on the field, setAccessible() is called, and then it can be set by the injection framework.

See an example here.

No magic, no custom VM.

like image 157
skaffman Avatar answered Sep 18 '22 01:09

skaffman


With the help of skaffman I coded this simple example on how to inject without setters. Perhaps it helps (It did to me)

//......................................................
import java.lang.annotation.*;
import java.lang.reflect.*;

//......................................................
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Inject {
}

//......................................................
class MyClass {

    @Inject
    private int theValue = 0;

    public int getTheValue() {
        return theValue;
    }
} // class

//......................................................
public class Example {

    //......................................................
    private static void doTheInjection(MyClass u, int value) throws IllegalAccessException {

        Field[] camps = u.getClass().getDeclaredFields();

        System.out.println("------- fields : --------");
        for (Field f : camps) {
            System.out.println(" -> " + f.toString());
            Annotation an = f.getAnnotation(Inject.class);
            if (an != null) {
                System.out.println("       found annotation: " + an.toString());
                System.out.println("       injecting !");
                f.setAccessible(true);
                f.set(u, value);
                f.setAccessible(false);
            }
        }

    } // ()

    //......................................................
    public static void main(String[] args) throws Exception {

        MyClass u = new MyClass();

        doTheInjection(u, 23);

        System.out.println(u.getTheValue());

    } // main ()
} // class

Run output:

------- fields : --------
 -> private int MyClass.theValue
       found annotation: @Inject()
       injecting !
23
like image 37
cibercitizen1 Avatar answered Sep 20 '22 01:09

cibercitizen1