Currently I have been thinking about the question however, I couldn't find a proper answer. Use case at hand is to create an implementation class for a particular custom annotation so that in the runtime I can simply generate it instead of a POJO.
For instance:
Annotation:
#interface CustomAnnotation {
String date();
}
At this stage I need a bean which happens to have the same fields as the annotation. Here I have two options either implement the annotation and create it in runtime or create a class to carry the information.
A)
Implementation of Annotation:
public class CustomAnnotationImpl implements CustomAnnotation {
private final String date;
public CustomAnnotationImpl(String date) {
this.date = date;
}
#Override
public String date() {
return this.date;
}
#Override
public Class<? extends Annotation> annotationType() {
return CustomAnnotation.class;
}
}
B)
public class CustomBean {
private final String date;
public CustomAnnotationImpl(String date) {
this.date = date;
}
public String getDate() {
return this.date;
}
}
Also keep in my mind that the bean and annotation will be always in sync meaning that bean actually will be always a copy of the annotation.
My question is that what would be the advantages and drawbacks of those, if any? I'm asking this because simply I haven't seen implementation of annotation myself.
I do not understand 100% your question, but it looks like other people already ask something like this.
Use cases for implementing annotations
Use cases for java annotation and more
Related
I have two classes: FriendRequest and FriendRequestDto.
I've defined a converter from FriendRequestDto to FriendRequest:
#Component
public class FriendRequestDtoToFriendRequestConverter implements Converter<FriendRequestDto, FriendRequest> {
#Override
public FriendRequest convert(FriendRequestDto dto) {
...
}
}
When I try to use it:
#RestController
#RequestMapping("/api/v1/friend-request")
public class FriendRequestController {
private final FriendRequestService friendRequestService;
private final ConversionService conversionService;
public FriendRequestController(
FriendRequestService friendRequestService,
#Qualifier("mvcConversionService")
ConversionService conversionService
) {
this.friendRequestService = friendRequestService;
this.conversionService = conversionService;
}
#PostMapping("/send")
public FriendRequestStatus send(#Valid #RequestBody FriendRequestDto friendRequestDto) {
return friendRequestService.saveFriendRequest(
conversionService.convert(friendRequestDto, FriendRequest.class)
);
}
}
I get a warning Argument 'conversionService.convert(friendRequestDto, FriendRequest.class)' might be null and a way to fix it: Replace with Objects.requireNonNull(conversionService.convert(friendRequestDto, FriendRequest.class)). This removes the warning.
I found out that the null check is needed because the convert method is marked with the #Nullable annotation.
However, it seems to me not a very good idea to write Objects.requireNonNull every time I want to convert something.
Is there a way to get rid of the warning without using the Objects.requireNonNull check?
I have a question, a little bit theoretical:
Assume, I have the following classes :
interface ReportInterface {
void execute();
}
class Report implements ReportInterface {
private final Repository rep;
Report(Repository ref){
this.rep = ref;
}
public void execute(){
//do some logic
}
}
class ReportWithSetter implements ReportInterface {
private final Repository rep;
private String release;
ReportWithSetter(Repository ref){
rep = ref;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
public void setRelease(String release){
this.release=release;
}
}
The second report needs an additional parameter release to work properly, but my interface is defined without parameters for execute method, so I work around it with a setter method, so it would look like:
ReportWithSetter rep2 = new ReportWithSetter (rep);
rep.setRelease("R1.1");
rep.execute();
So I don't like this additional rep.setRelease. I looks weird and artificial - a user of this class may be confused, and for example, if I make the class as a singleton bean in Spring, it is a source of potential error, if it is requested for the second time and somebody forgets to trigger rep.setRelease for the second time. Besides putting it into constructor (I want to make it a spring bean), what would be the best practice to handling this situation?
Assuming you are allowed to change the interface, here are a few solutions I can think of:
Solution #1
void execute(Optional<String> release);
or
void execute(#Nullable String release);
and then use them for Report class as execute(Optional.empty()) or execute(null).
Solution #2
void execute(String... release);
and then use it for Report class as execute() and for ReportWithSetter class as execute("R1.1").
Solution #3
Define both void execute(); and void execute(String release); in the interface. Then while implementing, throw UnsupportedOperationException in the method you don't need. For example, in Report class, you would do:
public void execute(){
//do some logic
}
public void execute(String release){
throw new UnsupportedOperationException("Use the overloaded method");
}
You can also make both these methods as default in the interface, so your implementation classes don't have to worry about implementing the unsupported method.
Use whichever is most readable and maintainable for you.
Solution 1: Spring Dependency Injection - Field Injection:
Spring's Dependency Injection works with reflection, so Setter methods are not required.
So if you make your Report class a Spring Bean and use #Autowired to inject another bean, then the Setter method is not required.
It would look like this:
#Component
class ReportWithRelease implements ReportInterface {
#Autowired private final Repository rep;
#Autowired private Release release;
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
I changed "String release" to "Release release", because making a bean of "String" would be also strange. So the "Release" class would have to contain your "String release".
If "String release" contains only some configured value, which does not change at runtime. Then you can use #Value to read its String value from a properties file.
Solution 2: Spring Constructor Injection:
Constructor injection is another option, which is even more recommended.
Then your Report bean would look like this:
#Component
class ReportWithRelease implements ReportInterface {
private Repository rep;
private Release release;
#Autowired
public ReportWithRelease(Repository rep, Release release) {
this.rep = rep;
this.release = release;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
Factory method patterns are good if you want to create instances of different classes of same interface.
class MyFactory {
ReportInterface createInstance(Class clazz, String... args) {
if (Report.class.equals(clazz)) {
return new Report();
}
if (ReportWithSetter.class.equals(clazz)) {
return new ReportWithSetter(args[0]);
}
throw new IllegalArgumentException(clazz.getName());
}
}
Spring of course offers autowiring, but introducing #AutoWire should be done for systematic purposes.
Here you can do with a two-stage execute, a factory.
class ReportFactory /*ReportWithSetter*/ {
private final Repository rep;
private final String release;
private final ReportInterface report = ...;
ReportFactory (Repository rep, String release) {
this.rep = rep;
this.release = release;
}
public ReportInterface report() {
return report;
}
}
new ReportFactory(rep, release).execute();
My usecase is something like this. My system has already has a configuration system, where we add configuration in a text file, similar to properties file but not exactly. I want to reuse the same configuration system. The configuration system provides this interface:
public interface ConfigurationProvider {
Boolean getBoolean(String key);
String getString(String key);
Long getLong(String key);
...
}
I want to use #Named annotation to get the configuration values injected, something like:
public ClassA {
String stringVal;
Long longVal;
#Inject
public ClassA(#Named("some_str_val" String strVal, #Named("some_long_val") Long longVal)) {
stringVal = strVal;
longVal = longVal;
}
}
I am not sure how to bind based on the annotation value.
class MyConfigModule extends AbstractModule {
ConfigurationProvider configProvider;
MyConfigModule(ConfigurationProvider configProvider) {
configProvider = configProvider;
}
public void configure() {
// Here, I would want to bind String annotated with Named to getString(annotation.value), but not sure how to do that
}
}
Something like
bind(String.class).annotatedWith(Names.named("property.name")).toInstance(configProvider.getString("property.name"));
which you can get fancy with or just manually add each property you expect to be in there. If your configProvider can iterate through fields, it might be easier.
I've got the following code:
package vb4.email;
import org.springframework.beans.factory.annotation.Value;
public enum ValidAddresses {
// TODO: Is there a cleaner way to switch debugs?
// How do we make this bean-able?
#Value("${email.addresses.defaults.support}")
DEFAULT_SUPPORT_ADDRESS("support#example.com"),
#Value("${email.addresses.defaults.performance}")
DEFAULT_PERFORMANCE_SUPPORT_ADDRESS("speed#example.com");
private final String email;
private ValidAddresses(final String email){
this.email = email;
}
#Override
public String toString()
{
return this.email;
}
}
As you can see from my #Value annotations, I'm looking to "beanify" this process. I want the benefits of the enumerable as a construct, but I'd like to make this configurable in our .properties file. Please keep in mind that the .properties file which has all the key=value pairs is used extensively throughout the site.
Please keep your answers on mark; I'm not looking to debate the validity of what is already in place. (Trust me I understand your frustration).
You can provide setters for your ValidAddresses enum and then use an initializer, smth like
#Configurable
public class EnumValueInitializer {
#Value("${email.addresses.defaults.support}")
private String support;
#PostConstruct
public void postConstruct() {
initializeAddressesEnum();
}
private void initializeAddressesEnum() {
ValidAddresses.DEFAULT_SUPPORT_ADDRESS.setEmail(support);
}
}
I hope it will be helpful. Good luck.
I'm trying to create a simple custom validator for my project, and I can't seem to find a way of getting seam to validate things conditionally.
Here's what I've got:
A helper/backing bean (that is NOT an entity)
#RequiredIfSelected
public class AdSiteHelper {
private Date start;
private Date end;
private boolean selected;
/* getters and setters implied */
}
What I need is for "start" and "end" to be required if and only if selected is true.
I tried creating a custom validator at the TYPE target, but seam doesn't seem to want to pick it up and validate it. (Maybe because it's not an entity?)
here's the general idea of my custom annotation for starters:
#ValidatorClass(RequiredIfSelectedValidator.class)
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface RequiredIfSelected {
String message();
}
public class RequiredIfSelectedValidator implements Validator<RequiredIfSelected>, Serializable {
public boolean isValid(Object value) {
AdSiteHelper ash = (AdSiteHelper) value;
return !ash.isSelected() || (ash.getStart() && ash.getEnd());
}
public void initialize(RequiredIfSelected parameters) { }
}
I had a similar problem covered by this post. If your Bean holding these values is always the same then you could just load the current instance of it into your Validator with
//Assuming you have the #Name annotation populated on your Bean and a Scope of CONVERSATION or higher
AdSiteHelper helper = (AdSiteHelper)Component.getInstance("adSiteHelper");
Also as you're using Seam your validators don't need to be so complex. You don't need an interface and it can be as simple as
#Name("requiredIfSelectedValidator")
#Validator
public class RequiredIfSelectedValidator implements javax.faces.validator.Validator {
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
//do stuff
}
}