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.
Related
With the following Java code:
public class Bean{
private String value;
public Bean(#NonNull String value) {
//Usually fail-fast validation can be added here if it is needed
this.value = value;
}
public String getValue() {return this.value;}
}
Is it possible to check the constructor argument value by means of the annotation, #NonNull at run time other than compile time? Personally I still did not find any checker-framework, which can do validation checking at run time. However, is it possible to implement an Annotation processor to do run time checking?
You should take a look at #NotNull from javax.validation.constraints.
I use it in my models and it throw a Constraint exception when I try to save a model with a null #NotNull value.
The import is import javax.validation.constraints.NotNull;
If you are using Spring and mongodb, you'll have to configure it so it works, I have found a piece of code somewhere on the Internet (can't remember where), you may use it:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
#Configuration
public class CustomRepositoryRestConfigurerAdapter {
#Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}
#Bean
public ValidatingMongoEventListener validatingMongoEventListener(
#Qualifier("localValidatorFactoryBean") LocalValidatorFactoryBean lfb
) {
return new ValidatingMongoEventListener(lfb);
}
}
Yes. Lombok's #NonNull is a runtime check which just inserts an if-statement with a throw:
With Lombok
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(#NonNull Person person) {
super("Hello");
this.name = person.getName();
}
}
Vanilla Java
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(#NonNull Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person is marked #NonNull but is null");
}
this.name = person.getName();
}
}
Misconception at your end: there is no single answer to your question.
Some annotations, when used on source code like this are mainly targeting compile time. Like some static analysis tool that analyses the data flow to tell you that you are violating "annotated" contracts here or there.
But some annotations are also "meant" to be used at runtime, for example to be used with "beans". Such objects might come in as parameter of a HTTP request, and then you have some framework checking if the content received as JSON for example is actually valid, according to the rules specified via annotations. See this tutorial for some examples.
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
I'm having some trouble using my values from a .properties file.
My my-properties.properties file looks something like this:
email.host=smtp.googlemail.com
email.port=465
Then my Configuration file looks like this:
#Configuration
#PropertySource("classpath:my-properties.properties")
class MyProperties{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
And then I'm trying to use it in this Email class:
#Component("MyProperties.class")
public class AutomatedEmail {
private String recipient;
private String fullName;
private String tempPassword;
private Email email;
#Value("email.from")
private String from;
...
public AutomatedEmail(){
}
public AutomatedEmail(final String recipient, final String fullName, final String tempPassword) throws EmailException {
this.recipient = recipient;
this.fullName = fullName;
this.tempPassword = tempPassword;
}
But it is always coming back saying its null. I've also tried an Autowired approach and setting up the entire email object in the MyProperties class, but that is null also after I call my Constructor
You need to surround the name in the properties file with curly brackets and a dollar sign to make a Spring expression.
#Value("${email.from}")
There's more info in this tutorial on spring values
Edit: Note that this will only work if the bean has been instantiated and managed by the Spring container. You won't be able to inject values into the bean if you just call new Email();.
Read through the spring doco on bean IoC to get a better understanding. And a bit more info on how to instantiate beans.
i am building a http API client that needs to call out to a specific endpoint like so:
public class MyApiClient {
private static final String ENDPOINT ="http://myapi....";
}
Here the endpoint won't change so its constant. However, I want to be able to override this for testing so that I can test against a mock http server for example.
Whats the best way to do this? Is it just to make it an instance variable and provide it with a starting value:
private String endpoint = ="http://myapi....";
public void setEndpoint(String endpoint){
...
}
Well, there are of course many solutions to this and one way of doing it is to use a system property with a default value:
private static final String DEFAULT_ENDPOINT = "http://myapi....";
private static final String ENDPOINT =
System.getProperty("my.endpoint", DEFAULT_ENDPOINT);
This way you get a configurable way of solving your problem. If you need even more flexibility when initializing your static constants you could also use a static initializer:
private static final String ENDPOINT;
static {
// do initialization here but do not throw any exceptions (bad practice)
// you can e.g. read from files etc...
// Then assign your constant...
ENDPOINT =
}
System properties are passed on the command line as -D parameters e.g:
java -Dmy.endpoint=http://...
But in my opinion, an even better approach is to actually inject the value to the class that is using it:
public class ClassThatIsUsingTheConfig {
private final String endpoint;
public ClassThatIsUsingTheConfig(final String endpoint) {
this.endpoint = endpoint;
}
public void someMethod() {
// use endpoint
}
}
And then, make the selection of which endpoint to use in the caller class. From a test case, this will be very easy to mock.
public class MyTest {
#Test
public void testMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(TEST_ENDPOINT);
var.someMethod();
}
}
public class MyProdClass {
public void prodMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(PROD_ENDPOINT);
var.someMethod();
}
}
You can read more about dependency injection here.
On a side note, if you are using some kind of framework for managing dependencies such as Spring Framework or CDI it is common to be able to inject properties and constants in various ways (e.g. based on which environment that is currently running). An example, when using Spring Framework you can declare all your constants in a property file and inject the property using annotations:
#Autowired
public ClassWhoIsUsingTheConfig(#Value("my.endoint") final String endpoint) {
this.endpoint = endpoint;
}
The property file for prod could be along the lines of:
my.endpoint=http://prodserver...
wheras the property file for test would look like this:
my.endpoint=http://testserver...
The approach of using a Dependency Injection engine allows for a very flexible way of handling external constants, paths, resources etc and simplifies your life when it comes to testing the code.
What is faster (and better) ? :
Load variables to a special
static object and when a variable
from configuration file is needed
get variale from static object's
field.
Copy configuration
variable to a local field when
creating new object which needs a
configuration variable.
I prefer instance level myself, as long as you aren't doing it excessively (i.e. Don't read the configuration every time you instantiate something).
Static configurations will give you heartache. Especially for testing.
The best solution in my mind is to use a framework like Spring (or Guice) to inject configuration type information into your objects.
I'd say use on-demand caching. Look at the MapMaker from guava-collections. If you doesn't want to add additional dependency then I'd prefer option 1.
I would abstract the configuration with an interface and provide strategies like:
public interface Config {
public String getUrl();
public String getName();
}
public class PropertiesConfig implements Config {
private final String url;
private final String name;
public PropertiesConfig(String filepath) {
Properties props = // read properties from file input stream
this.url = props.getProperty("url", "");
this.name = props.getProperty("name", "");
}
// getters from interface
}
public class SpringConfig {
private final String url;
private final String name;
public SpringConfig(String contextPath) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(contextPath);
this.url = (String) ctx.getBean("url");
this.name = (String) ctx.getBean("name");
}
// getters from interface
}
Etc., you could provide a bunch of strategies obviously.
public class Application {
private final Config config;
public Application(Config config) {
this.config = config;
}
public String doWork() {
return Client.url(config.getUrl()).get();
}
}