Changing Java annotation parameter default - java

I use a library that provides an annotation #LibraryAnnotation with a Boolean parameter parameter. The default is set to true by the authors of the library.
Unfortunately, in almost all my use cases, I prefer the annotation with parameter = false. To achieve the desired behavior, I use #LibraryAnnotation(parameter=false) instead of #LibraryAnnotation every time. This is error prone since one easily forgets to set the parameter.
I am wondering if there is a way to simplify things by changing the default value for the parameter of #LibraryAnnotation or by defining a custom annotation that behaves like #LibraryAnnotation(parameter=false), but does not require setting a parameter.
(In this particular case, the library is lombok, but the question could be relevant for parametrized annotations provided by any library. Update: Lombok offers default parameter configuration via a lombok.config file, but I am still interested in a general solution.)

You can define your own annotation and use that instead. Something like:
#LibraryAnnotation(parameter = false)
public #interface MyLibraryAnnotationFalse {
}

Related

How to make a data field optional (not required) in JAX-RS?

I have a RESTapi written using Jersey Framework. Along with it there is a POJO class. Now, my need is how do I make a particular field optional in my POJO so that the api will work regardless of that optional field? I want the API should work in both the cases, i.e
if I give that optional parameter then also,
if I don't give then also it should work.
Java 8's Optional was mainly intended for return values from methods, and not for data properties of Java classes(POJO), as described in Optional in Java SE 8:
Of course, people will do what they want. But we did have a clear
intention when adding this feature, and it was not to be a general
purpose Maybe or Some type, as much as many people would have liked us
to do so. Our intention was to provide a limited mechanism for library
method return types where there needed to be a clear way to represent
"no result", and using null for such was overwhelmingly likely to
cause errors.
The key here is the focus on use as a return type. The class is
definitively not intended for use as a property of a Java Bean.
Witness to this is that Optional does not implement Serializable,
which is generally necessary for widespread use as a property of an
object.
[credits] : https://blog.joda.org/2014/11/optional-in-java-se-8.html
I'm guessing you are referring to the serialisation of fields in your POJO. Since you have not stated which version of jackson you are using, you'll have to use one of these annotations to allow nulls:
Can be used on either class or getter:
#JsonInclude(Include.NON_NULL)
If you are using Jackson <2.x, use this:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

Guice multiple annotations

I have an interface called StatsStore. I have 2 implementations of this store. An in-memory and an SQL implementation called InMemoryStatsStore and SqlStatsStore. In order to inject them I've create 2 annotations #InMemoryStore and #SqlStore. the injections are:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(StatsStore.class)
.annotatedWith(SqlStore.class)
.to(SqlStatsStore.class);
Now I want to add a new layer of annotation to separate between InMemoryStringStore and InMemoryNumberStore but I can't add more than one annotation to the binding lines e.g. the following does not compile:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
.to(InMemoryNumberStore.class);
How can I add more than one annotation without using a single named one which would be quite complicated the more layers I add to it?
The other solution I had in mind is Injecting twice:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(InMemoryStatsStore.class)
.annotatedWith(NumberStoreAnnotation.class)
.to(InMemoryNumberStore.class);
Thanks all.
As Amit said, you can't have more than one #BindingAnnotation apply to any given injection. Internally, Guice works like a Map<Key, Provider> where a Key is a possibly-parameterized class with an optional single annotation instance. However, because these are instances, you're welcome to create your own instantiable annotation that works the way Named works.
#Inject #InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
#Inject #SqlStore(STRING) StatsStore sqlStringStore;
// or
#Inject #Store(dataType=NUMBER, backend=SQL) sqlNumberStore;
The annotation must have the fields defined like so. (If you have one element named value, you can omit the property name per JLS 9.7.3.) Equal annotations are defined as in the Annotation.equals docs.
public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }
#BindingAnnotation #Retention(SOURCE) #Target({ FIELD, PARAMETER, METHOD })
public #interface Store {
DataType dataType();
Backend backend();
}
That works nicely for #Provides, when you can invoke the annotation the same way you inject it, but how can you create a factory method for instances like Names.named? For that, you'll need to do one of the following:
Create an anonymous implementation, with accessors for each attribute as well as correct implementations of equals and hashCode. Note that the hashCode contract is much stricter than for Object, but you can get compatible implementations from Apache annotation utils or similar libraries.
Use AnnotationLiteral, which provides equals and hashCode implementations for arbitrary subclasses.
Use Google Auto or a similar code generator to generate code for a compatible implementation for you. Familiarity with this type of solution is particularly useful for Android and other memory-constrained environments for which reflection is slow, though such environments usually preclude you from using Guice. (#Qualifier annotations work the same way in other JSR-330 compatible dependency injection frameworks, though, including Dagger.)
If the above seems a little complicated, or if you want more complex logic than Guice's map-based implementation can accomplish, one alternative is to add a layer of indirection that you control:
public class StoreStore {
#Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
// ...
// You can also inject the Injector to call getInstance with a class literal.
public StatsStore getStore(DataType dataType, Backend backend) {
// This can also be a switch or any other sort of lookup, of course.
if (dataType == NUMBER && backend == IN_MEMORY) {
return inMemoryNumberStoreProvider.get();
} // ...
}
}
You can't do that:
#BindingAnnotation tells Guice that this is a binding annotation. Guice will produce an error if ever multiple binding annotations apply to the same member.
You could use named bindings instead, or you should consider redesigning your solution.

Can MapStruct be told to not perform automatic mappings?

I have a rather big bean (~ 100 properties) that is mapped into several smaller objects. It may occur that the smaller target objects have properties with the same name as in my source bean, but not with the same semantic meaning.
I would like MapStruct to behave in this specific case to map only what I explicitly tell using a #Mapping annotation and not perform the usual automatic mapping.
The MapStruct documentation tells me just this:
In the generated method implementations all readable properties from the
source type (...) will be copied into the corresponding property
in the target type (...).
I didn't find any configuration option switching this behavior off.
Can it be done?
Switching off implicit field mapping is possible via #BeanMapping(ignoreByDefault = true) mapping method annotation since MapStruct 1.3. From MapStruct 1.3.1 Reference Guide:
By means of the #BeanMapping(ignoreByDefault = true) the default
behavior will be explicit mapping, meaning that all mappings have to
be specified by means of the #Mapping and no warnings will be issued
on missing target properties.
As stated in Mohamed's comment, you could ignore these properties explicitly.
There is no switch as you describe it. Personally I'd probably write that specific mapping from hand instead of explicitly configuring all the mappings through annotations. Granted, you'd still benefit from type conversion etc., so it may still be beneficial, it really depends on your use case.
I had a similar problem like you say, I solved it using decorators
#Mapper
#DecoratedWith(PersonMapperDecorator.class)
public interface PersonMapper {...}
see the documentation (MapStruct 1.2.0.Final Reference Guide), chapter: 12. Customizing mappings
I hope that it is also useful for you

Java Simple XML library: set 'strict' and 'required' values to false

I'm using the Simple XML library. Most of my models should be parsed using the #Root(strict = false) and most elements/attributes should be parsed with #Element(required = false). Unfortunately the default value for both annotations is true, but I'd like to avoid manually setting it to false on almost every object and field. Is there a setting somewhere I could use, perhaps as an argument passed to the Persister object? I haven't been able to find a solution so far while reading the documentation.
The SimpleXML library provides a #Default annotation which controls default behavior for all elements and attributes, including whether or not they are required. This allows you to set one annotation on the class and not have to override on a property-by-property basis.
#Default(required=false)
public class YourModelObject {
// your elements and attributes
}

Java annotation example in official docs

While reading the Oracle documentation on annotations (quite new to this concept), I came across the following snippet in the beginning (link at the bottom). I am not clear on what the example is illustrating. Is the public #interface definition an enhanced version of a normal interface definition? id(), engineer() etc are methods that return default values if not specified in the interface implementation? But then the instantiation is confusing, is it providing an implementation of an interface where id() returns 2868724 etc? Also not clear what the function travelThroughTime() is for. Any clarifications appreciated:
/**
* Describes the Request-For-Enhancement(RFE) that led
* to the presence of the annotated API element.
*/
public #interface RequestForEnhancement {
int id();
String synopsis();
String engineer() default "[unassigned]";
String date(); default "[unimplemented]";
}
#RequestForEnhancement(
id = 2868724,
synopsis = "Enable time-travel",
engineer = "Mr. Peabody",
date = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }
http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
To break down your questions:
Is #interface just an enhancement of interface?:
No, #interface is declaring something quite different from a standard interface- you are essentially declaring an annotation type. Making this declaration enables the declared thing to be used as an annotation in other code. So the declaration:
public #interface RequestForEnhancement
enables the annotation #RequestForEnhancement to be used in later code.
An annotation describes metadata for a method or a class. The #RequestForEnhancement annotation, for example, might be placed in front of a method in another class to indicate that some developer wants that method to be changed in some way.
Declaring an interface, by contrast, is declaring the signature of a group of functions. Classes which later implement an interface must then provide implementations of those functions.
What are the "methods" (synopsis(), engineer(), etc.) in the annotation body for? These are not really methods like you would be used to seeing in a class or interface definition. Instead, these represent fields that the annotation you've just declared has. A #RequestForEnhancement annotation on a method should indicate what the requested change to the method is, and possibly who is expected to implement the enhancement to the method. Thus the fields synopsis and engineer are fields that can be included in the annotation.
What does this section mean?:
#RequestForEnhancement(
id = 2868724,
synopsis = "Enable time-travel",
engineer = "Mr. Peabody",
date = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }
This is an example of using the annotation that we've declared in the block starting with #RequestForEnhancement. Usages like this will likely occur all over your codebase, in many different classes, once the annotation has been defined. In this particular example, there is a method travelThroughTime(Date destination) in some class which apparently doesn't work very well. Some developer coming across the method thought it should be improved by making it do what it appears to claim to do (travel through time). That developer decided to reflect his request by putting an #RequestForEnhancement annotation on the method with some information about when the request was made, who was expected to make the enhancement, etc.
Sure, but how do you use the contents of an annotation for anything useful? (A question I'll ask for you :-) )
So let's say I want to write a tool which looks through all of my code for methods annotated with #RequestForEnhancement and send an e-mail to the engineers listed in the request, along with information about the annotation and the request for enhancement. How would I get started?
The basic mechanism to find out what methods have an annotation and the way to get values from the annotation is through Java reflection. A tutorial which includes an example of annotations and reflection is here (it's actually a good tutorial on annotations in general).
So sure, you can use reflection to get info out of these annotations, but when would you run a tool to use the info from the annotations? (another one I'll ask for you) Java provides the ability for you to define annotation processors which use annotation information when your code is compiled. Here's what looks like a reasonable tutorial. You can also use the information in your annotations at runtime. If you've ever used JavaFX, for example, you may have noticed that annotations can affect runtime behavior (adding #FXML to a field helps JavaFX fill that field with a value defined in your fxml).

Categories

Resources