Reputation: 3155
I am experimenting with Weld. Given the following prerequisites...
public interface Printer {
void print(Job job) throws IOException;
interface Job { void feed(PrintStream out); }
}
@Qualifier
@Target({ METHOD, FIELD, PARAMETER, TYPE })
@Retention(RUNTIME)
public @interface StandardOutput { }
@Qualifier
@Target({ METHOD, FIELD, PARAMETER, TYPE })
@Retention(RUNTIME)
public @interface StandardError { }
... I would like to provide two standard instances, one for the standard output stream and one for the standard error stream (JSE environment):
public class PrintStreamPrinter implements Printer {
private final PrintStream out;
@Produces static final @StandardOutput PrintStreamPrinter
stdout = new PrintStreamPrinter(System.out);
@Produces static final @StandardError PrintStreamPrinter
stderr = new PrintStreamPrinter(System.err);
private PrintStreamPrinter() { throw new AssertionError(); }
public PrintStreamPrinter(final PrintStream out) {
this.out = Objects.requireNonNull(out);
}
public void print(final Job job) throws IOException {
job.feed(out);
if (out.checkError()) throw new IOException();
}
}
Now I can use this like so:
@Inject @StandardOutput Printer printer;
and use it happily ever after.
However, this fails if I remove the useless private constructor without parameters from the PrintStreamPrinter
class. It took me a while to figure this and I don't know why. Obviously, the implementation is never called, so why does it have to exist in the first place? Note that I am using the @Dependent
scope here, so no client proxy has ever to be created.
This is the exception I am getting from Weld SE 2.0.1.Final after removing the useless private constructor:
Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Printer] with qualifiers [@StandardOutput] at injection point [[BackedAnnotatedField] @Inject @StandardOutput private com.company.mavenproject1.Main.printer]
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:404)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:326)
at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:177)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:208)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:520)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:70)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
What's more interesting: If the private constructor is present, the Weld logs tell me:
WELD-000106 Bean: Producer Field [PrintStreamPrinter] with qualifiers [@StandardOutput @Any] declared as [[BackedAnnotatedField] @Produces @StandardOutput final static com.company.mavenproject1.PrintStreamPrinter.stdout]
WELD-000106 Bean: Producer Field [PrintStreamPrinter] with qualifiers [@StandardError @Any] declared as [[BackedAnnotatedField] @Produces @StandardError final static com.company.mavenproject1.PrintStreamPrinter.stderr]
These lines are missing when the constructor is removed.
Is this a bug or a feature?
Upvotes: 2
Views: 1338
Reputation: 5378
In order for CDI to properly proxy your classes you must have either a no args constructor (thought it had to be public, could be implementation though) or a constructor marked with @Inject
.
Take a look at the specification source.
Upvotes: 3