I´m currently working through a JavaEE7 tutorial and I´ve came to an exercise I can´t solve. I have to split my logging into tech log and operational log using qualifiers. Here´s the class where I define these qualifiers:
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
*
* #author jalexakis
*/
public class Logs {
#Qualifier
#Target({FIELD, PARAMETER})
#Retention(RUNTIME)
public #interface TecLog {}
#Qualifier
#Target({FIELD, PARAMETER})
#Retention(RUNTIME)
public #interface OperationalLog{}
}
Now I have to change this method,
#Produces
public Logger produceLog(InjectionPoint injectionPoint){
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName(), "messages");
}
into two methods, one for #TecLog and one for #OperationalLog. How do I do this? I tried annotating the method with the qualifiers, but I get an "annotation type not applicable to this kind of declaration"-error.
First remark, even if it might work (I never tested), I wouldn't recommend defining qualifier as inner static classes. In your case there are even non static class so I don't see how you could use them.
To make your life simpler make your both qualifier top level class in your application.
Second point, qualifiers can be applied on type, method, parameter and field so the correct target would be:
#Target({ TYPE, METHOD, PARAMETER, FIELD })
That's the origin of your error by the way
So to sum up here is the correct definition for your qualifiers
#Qualifier
#Target({ TYPE, METHOD, PARAMETER, FIELD })
#Retention(RUNTIME)
public #interface TecLog {
}
and
#Qualifier
#Target({ TYPE, METHOD, PARAMETER, FIELD })
#Retention(RUNTIME)
public #interface OperationalLog{
}
as they accept METHOD as target you can now apply them yo your producers
Related
I have the following Groovy classes:
#Canonical
abstract class BaseEntity {
Long id
String refId
}
#Canonical
#TupleConstructor(includeSuperFields = true, includeFields = true)
#ToString(includeSuperProperties = true)
class GroceryItem extends BaseEntity {
String name
Integer quantity
}
Then at runtime I'm creating an instance of GroceryItem:
GroceryItem cheeseWedges = new GroceryItem(1L,
'067e6162-3b6f-4ae2-a171-2470b63dff00', 'Cheese Wedges', 4)
When this constructor runs I get the following exception:
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.example.myapp.GroceryItem(java.lang.Long, java.lang.String, java.lang.String, java.lang.Integer)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1732)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1532)
at org.codehaus.groovy.runtime.callsite.MetaClassConstructorSite.callConstructor(MetaClassConstructorSite.java:49)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
What's going on here? What's the fix? Is the fact that BaseEntity is abstract causing problems here? I seem to remember having a similar issue with these annotations + ABC's a few years ago.
Hope you might aware that Canonical itself is combination of ToString, TupleConstructor and EqualsAndHashCode.
Here since you are explicitly specifying TupleConsturctor with options, Canonical may be removed for sub-class i.e., GroceryItem.
Apart from it, need to includeSuperProperties=true options for TupleConsturctor in order to achieve the desired behaviour. Here is blog which you can refer for more details.
Since the base class is abstract, annotation is not required.
In case if the base class is regular class, and you want to call super() of base class constructor, then callSuper=true option can be included to TupleConstructor annotation of child class. Of course, Canonical would be required that time for base class as well.
In case if a property is defined with access modifier in base class, say public String description then includeSuperFields=true option needs to be added to TupleConstructor of child class.
Here is fixed code snippet:
import groovy.transform.*
abstract class BaseEntity {
Long id
String refId
}
#TupleConstructor(includeSuperProperties=true)
#ToString(includeSuperProperties=true)
class GroceryItem extends BaseEntity {
String name
Integer quantity
}
def item = new GroceryItem(1L,'067e6162-3b6f-4ae2-a171-2470b63dff00', 'Cheese Wedges', 4)
println item.toString()
You can quickly try it online demo
I have the following Groovy classes:
enum Protocol {
File,
Ftp,
Sftp,
Http,
Https
}
#Canonical
abstract class Endpoint {
String name
Protocol protocol
}
#Canonical
#TupleConstructor(includeFields=true, includeSuperFields=true)
class LocalEndpoint extends Endpoint {
}
class MyAppModule extends AbstractModule {
#Override
protected void configure() {
// Lots of stuff...
}
// Lots of other custom providers
#Provides
Endpoint providesEndpoint() {
new LocalEndpoint('fileystem', Protocol.File)
}
}
Don't worry about why I'm using a custom provider for the Endpoint instead of just:
bind(Endpoint).toInstance(new LocalEndpoint('fileystem', Protocol.File))
I'm 99.999% sure that's outside of this problem and is coded that way because of how the full (very large) code is wired.
My problem is that Guice and/or Groovy cannot find a constructor for LocalEndpoint that takes a String and Protocol argument:
1) Error in custom provider, groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.example.myapp.model.LocalEndpoint(java.lang.String, com.example.myapp.model.Protocol)
at com.example.myapp.inject.MyAppModule.providesEndpoint(MyAppModule.groovy:130)
while locating com.example.myapp.model.Endpoint
for parameter 2 at com.example.myapp.inject.MyAppModule.providesConfig(MyAppModule.groovy:98)
at com.example.myapp.inject.MyAppModule.providesConfig(MyAppModule.groovy:98)
while locating com.example.myapp.config.MyAppConfig
It then spits out a large stack trace with the following listed as the cause:
Caused by: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.example.myapp.model.LocalEndpoint(java.lang.String, com.example.myapp.model.Protocol)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1731)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1534)
Hopefully this is something that I can tweak by modifying Endpoint and/or LocalEndpoint, perhaps I need to pass some special parameters into the #Canonical/#TupleConstructor annotations or something. Any ideas?
I think you need to add includeSuperProperties in the TupleConstructor annotation, and that seems to resolve it, even by itself:
#TupleConstructor(includeSuperProperties=true)
So the whole thing would be:
#Canonical
abstract class Endpoint {
String name
Protocol protocol
}
#Canonical // You may not need this anymore
#TupleConstructor(includeSuperProperties=true)
class LocalEndpoint extends Endpoint {
}
I wanted to implement the factory pattern with CDI. Here we have the business case example:
A client provides a string representing a type. Depending on this type the factory returns an implementation of an interface.
I know that there are a lot of questions flying around concerning factory pattern and CDI. The difference I have here is that I resolve the implementation returned by the factory based on a runtime parameter.
I was thinking of using a producer method but then I can not think of how to inject the resolved implementation into the bean where the implementation is needed since this is a runtime parameter which is not necessarily known at contruction time.
So I thought of the pretty straight forward way of using the Instance class.
Here is the basic implementation :
// the interface. Instances of this class are returned from the factory
public interface Product {
}
// one implementation may be returned by the factory
#ProductType("default")
public class DefaultProduct implements Product {
}
// another implementation may be returned by the factory
#ProductType("myProduct")
public class MyProduct implements Product {
}
// the qualifier annotation
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.TYPE})
public #interface ProductType {
String value();
}
// the Annotation implementation to select
// the correct implementation in the factory
public class ProductTypeLiteral extends AnnotationLiteral<ProductType>
implements ProductType {
private String type;
public ProductTypeLiteral(String type) {
this.type = type;
}
#Override
public String value() {
return type;
}
}
// the factory itself. It is annotated with #Singleton because the
// factory is only needed once
#Singleton
public class Factory {
#Inject
#Any
private Instance<Product> products;
public Product getProduct(String type) {
ProductTypeLiteral literal = new ProductTypeLiteral(type);
Instance<Product> typeProducts = products.select(literal);
return typeProducts.get();
}
}
In my opinion using Instance is very sophisticated.
But this has one major drawback:
Everytime you cal the Instance.get() method you retrieve a new Instance of Product. This may be fine but the Instance instance keeps a reference of the returned instance internally. So as long as the Factory lives and each time the Instance.get() is called the more instances of Product will exist in the memory and never get garbage collected because a reference is still hold in Instance.
I thought of not making the Factory a singleton but that just shifts the problem and does not solve it. And of course it is against the factory pattern.
Another solution I tried was to iterate through the Instance instead of selecting an implementation with the help of the annotation:
#Singleton
public class Factory {
#Inject
#Any
private Instance<Product> products;
public Product getProduct(String type) {
Product product = null;
for(Product eachProduct : products) {
ProductType productType = eachProduct.getClass().
getAnnotation(ProductType.class)
if(productType.value().equals(type) {
product = eachProduct;
break;
}
}
return product;
}
}
Basically this is working. Now each time depending on the given type I retrieve the same instance of Product. That way the memory is not consumed.
But I don't like it to iterate over a collection when I have the possibility to resolve the correct implementations more elegantly.
Do you have any ideas which may solve the problem? Otherwise I may have to keep the iteration solution.
Herein lies your problem. Instance keeps reference to instances you obtain from it using get() because it is responsible for reclaiming them when they go out of scope (i.e. when the injected Instance goes out of scope. But because you made your factory a singleton, it will never go out of scope. So, make your factory a short-lived scope, like #RequestScoped or even #Dependent, that way all the returned instances will be reclaimed properly.
Maybe it can help you:
Create qualifiers:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface MyProduct{
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface DefaultProduct{
}
In Factory class:
#Singleton
public class Factory {
public Product getProduct(#MyProduct MyProduct product, #DefaultProduct DefaultProduct defaultProduct) {
//What you wanna do
}
}
Im trying use a Java annotation in a Groovy class but have trouble to set a static field of a java class as a parameter:
The Annotation: Id.java
package x.y.annotations;
import java.lang.annotation.ElementType;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Id {
public Class<Adapter> adapter();
public Class<Object> targetType();
public String targetAttribute();
public String onDelete();
}
The java class with the static fields: XPerson.java
package x.y.static.domain;
public class XPerson {
public static String ID;
}
And the groovy class, where the problem occurs: Person.groovy
package x.y.domain
import x.y.annotations.Id
import x.y.static.domain.XPerson
class Person {
#Id(adapter = Adapter, targetType = XPerson, targetAttribute = XPerson.ID, onDelete = "delete")
long id
}
Eclipse marks the "targetAttribute = XPerson.ID" part with:
Groovy:expected 'x.y.domain.XPerson.ID' to be an inline constant of type java.lang.String not a property expression in #x.y.annotations.Id
I also tried things like "XPerson.#ID" or defining a getter for the ID field, but nothing helped.
Any hints would be great.
Regards,
michael
I have found a related issue in the Groovy JIRA. It is a bug. Should work. See https://issues.apache.org/jira/browse/GROOVY-3278
Annotation values may only be compile-time constant expressions. Making the field final is an option. (With the caveat that the field can't be initialized in a static initializer/etc. as the snippet implies.)
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.