Is it possible to create a package-scoped constructor in Groovy beans?
If I drop public from the constructor, then by default, it becomes a public constructor.
I read about #PackageScope annotation, but it doesn't allow me to apply it on the constructor.
The reason I want package-scoped constructor in Groovy beans is to force Java code to use the corresponding bean builders to instantiate the Groovy bean classes, and not rely on the Groovy bean's constructor. The builders are separate classes that sit in the same package as the Groovy beans.
Thank you.
Done in 2.4.0-beta-1. Seems like it simply wasn't requested before.
How does protected sound?
I wrote an example with three files: a.Foo.java, b.Hidden.groovy, b.NoProblem.java:
a.Foo.java:
package a;
import b.Hidden;
public class Foo {
Hidden hid = new Hidden(); // Not compiling with:
// "The constructor Hidden() is not visible"
}
b.Hidden.groovy:
package b
class Hidden {
protected Hidden() {
}
}
b.NoProblem.java:
package b;
public class NoProblem {
Hidden hid = new Hidden(); // Compiles fine
}
Related
I have a Repository interface that has two implementations. One reads data from a locally stored CSV file while the other reads from an Amazon Dynamo DB. I would like to be able to switch between which implementation I'm using based on an application property or custom build profile. I would normally use a Factory to retrieve the correct class at runtime, but I would like to do this with injection if possible.
I found a similar question using Spring boot but couldn't find an equivalent that would work in Quarkus Spring choose bean implementation at runtime
I also tried implementing a Configuration class similar to what is found in the docs here but again didn't have much luck. https://quarkus.io/guides/cdi-reference#default_beans
It feels like I'm missing something obvious so any pointers would be much appreciated.
Here is a simple example of my classes:
#ApplicationScoped
public class ExampleService {
#Inject
ExampleRepository repository;
public List<Data> retrieveData() {
return repository.retrieveData();
}
}
public interface ExampleRepository {
List<Data> retrieveData();
}
#ApplicationScoped
public class DynamoRepository implements ExampleRepository {
#Override
public List<Data> retrieveData() {
//Get Data from DynamoDb
}
}
#ApplicationScoped
public class CsvRepository implements ExampleRepository {
#Inject
CsvBeanHandler csvBeanHandler;
#Inject
LocalFileReader fileReader;
#Override
public List<Data> retrieveData() {
// Get data from CSV
}
}
I currently also have the following in my application.yml:
com:
example:
application:
storage-type: 'CSV' # OR AMAZON_DYNAMO_DB
It looks like they've added this directly to the documentation:
https://quarkus.io/guides/cdi-reference#declaratively-choose-beans-that-can-be-obtained-by-programmatic-lookup
I feel a bit guilty pasting this much, but it's the SO way.
I can add that it is NOT like a Guice 'binding'; BOTH classes will be instantiated, but only one will be injected. Also unlike Guice, you cannot inject the interface (or I did it wrong) - you have to do what's shown below, with Instance.
Personally I just use constructor injection and then drop the value of the Instance wrapper into a final field, so I'm not crying about the extra step. I do miss the power and explicit bindings possible with Modules ala Guice, but the simplicity here has its own value.
5.16. Declaratively Choose Beans That Can Be Obtained by Programmatic Lookup
It is sometimes useful to narrow down the set of beans that can be
obtained by programmatic lookup via javax.enterprise.inject.Instance.
Typically, a user needs to choose the appropriate implementation of an
interface based on a runtime configuration property.
Imagine that we have two beans implementing the interface
org.acme.Service. You can’t inject the org.acme.Service directly
unless your implementations declare a CDI qualifier. However, you can
inject the Instance instead, then iterate over all
implementations and choose the correct one manually. Alternatively,
you can use the #LookupIfProperty and #LookupUnlessProperty
annotations. #LookupIfProperty indicates that a bean should only be
obtained if a runtime configuration property matches the provided
value. #LookupUnlessProperty, on the other hand, indicates that a bean
should only be obtained if a runtime configuration property does not
match the provided value.
#LookupIfProperty Example
interface Service {
String name();
}
#LookupIfProperty(name = "service.foo.enabled", stringValue = "true")
#ApplicationScoped
class ServiceFoo implements Service {
public String name() {
return "foo";
}
}
#ApplicationScoped
class ServiceBar implements Service {
public String name() {
return "bar";
}
}
#ApplicationScoped
class Client {
#Inject
Instance<Service> service;
void printServiceName() {
// This will print "bar" if the property "service.foo.enabled" is NOT set to "true"
// If "service.foo.enabled" is set to "true" then service.get() would result in an AmbiguousResolutionException
System.out.println(service.get().name());
}
}
If your request is to bind at startup time the right implementation based on a configuration property, I suppose your problem may be resolved used #Produces annotation:
public class ExampleRepositoryFactory {
#Config("storage-type")
String storageType;
#Produces
public ExampleRepository dynamoInstance() {
return storageType == "CSV" ? new CsvRepository() : new DynamoRepository();
}
}
I have a class A which is kind of a wrapper over class B just to make B Serializable. Now I have class C in which I need to inject class A to be instantiated with attributes 'a' and 'b'. How can this be achieved?
The following is my code:
Class A extends B {
public A(int a, int b){
super(a,b);
}
class C{
#Inject
A objA; //will not work
}
Generally, its a good design practice not to pass data through constructor for injectable services. make your services as stateless and reusable as much as possible.
If that's not possible, you can check on CDI producer semantics here: Using producer methods and Fields
I think I agree with maress in that you're probably doing something fundamentally wrong, but without your entire use case, I'll offer the following:
Your class A, as it stands, cannot be injected into C because it is not a CDI bean. In order to be a CDI bean, it must have either a no-arg constructor or a constructor annotated with #Inject.
In this case, even if you annotate your constructor with #Inject:
#Inject
public A(int a, int b) { ... }
You still will not be able to inject A into C. The problem is that there many ways to satisfy that constructor. The container will not know which ints you mean to inject. That is, did you want it to instantiate an A(0,0) or an A(1,2) or an A(-12, 5001) or ... ?
You have a few options. You can use a qualifier (such as #Named) to disambiguate the particular ints that you want to inject:
#Inject
public A(#Named("int1") int a, #Named("int2") int b) {...}
The qualified ints can be generated via a producer method:
#Produces #Named("int1")
public int get_int1() { return 5; }
#Produces #Named("int2")
public int get_int2() { return 6; }
Alternately, you could use a producer method to produce instances of your A:
#Produces
public A get_A() { return new A(5,6); }
I'm trying to dynamicly crate an annotation that will dynamicaly add an #XmlElement annotation to every field in a class using metaprogramming and AST. I'm having problems creating the annotations and applying them to the fields properly.
The code i have is formatted here: http://pastebin.com/60DTX5Ya
import javax.xml.bind.annotation.XmlElement
#GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
class WebserviceAnnotationModifier implements ASTTransformation {
#Override
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
if (!astNodes) return
if (!astNodes[0] || !astNodes[1]) return
if (!(astNodes[0] instanceof AnnotationNode)) return
if (!(astNodes[1] instanceof ClassNode)) return
ClassNode node = (ClassNode)astNodes[1]
List fields = node.getFields()
fields.each {FieldNode field ->
field.addAnnotation(ClassHelper.make(new XmlElement.DEFAULT()));
}
}
}
#Retention(RetentionPolicy.SOURCE)
#Target([ElementType.TYPE])
#GroovyASTTransformationClass(classes =[WebserviceAnnotationModifier])
public #interface WebresourceAnnotation{}
#WebresourceAnnotation
class TestPerson{
String name;
String lastName;
int Age
}
Am i approaching this all wrong? The reason i do this is i have a domain that is still in the making and i'd like to just go in and apply the annotation to all fields. Couldn't find any examples of annotations added during compilation. Is this not possible?
Writing codes using Groovy AST Transformation alone does not work with the Grails reloading mechanism. Here's a proper way to implement AST transformation for a Grails app.
Your transformer class must extends AbstractGrailsArtefactTransformer.
Your transformer class must be annotated by #AstTransformer.
You class must be put under org.codehaus.groovy.grails.compiler or its sub-package. In my case I use org.codehaus.groovy.grails.compiler.zk and it's working fine.
Implement shouldInject() to match only classes you want, in this case domain classes.
Override performInjection() and write your codes there.
Pack your transformer and releated classes into a .jar file, or Grails compiler does not load it.
I have a collection of Processor beans in my application along with a factory for creating them.
public abstract class Processor {
public Processor(String config) { .... }
public abstract void process() throws Exception;
}
public class Processor1 extends Processor {
public Processor1(String config) { super(config);..}
public void process() {....}
}
public Processor newProcessor(String impl, String config) {
// use reflection to create processor
}
Can I use CDI to replace the factory class/method? And instead use a #Produces?
I tried using the following to iterate or select the instance I wanted. But Weld tells me that allProcessorInstances.isUnsatisfied() == true. I had to create default no-args ctor in order for Weld to find my Processor subclasses.
#Inject #Any Instance<Processor> allProcessorInstances;
Is there any way to tell the CDI container to use the constructor I want it to use? Or am I thinking about this problem the wrong way?
To use the constructor you'd need to annotate it with #Inject, however, every param on the constructor must itself be a bean or something in the CDI scopes.
Using a producer method and having that take an InjectionPoint as a param, then having your configuration be part of an annotation would work.
I use #XmlAccessorType(XmlAccessType.NONE) in package-info.java for my.package which means JAXB should care only about annotated elements. However, when I run my JUnit test with un/marshalling code for simple POJO MOXy just screams about every class (even from package without jaxb.properties or from other maven modules which are referenced in dependencies) in this manner:
Exception Description: The class other.maven.module.package.class requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported.
I haven't encountered such issue with Metro (reference implementation, but it has other defects for my usage) and unfortunately I really can't modify every class in this way.
I have been able to verify this issue, the following bug has been entered to track this issue.
https://bugs.eclipse.org/334681
Issue summary:
For the following object model:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
#XmlAccessorType(XmlAccessType.NONE)
public class Foo {
private Bar bar;
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
and:
public class Bar {
public Bar(String name) {
}
}
The EclipseLink MOXy JAXB implementation is processing the Bar class although it should not be, because it is not mapped.