What are the recommended approaches for generating routes in a java-based Spring MVC webapp? I'd like to avoid hard-coding paths throughout the application.
Assuming we are talking about paths RequestMappings etc.
In my application I have a single class with with a bunch of public static final constants that I reference in the #RequestMapping annotations.
So the constants might look like this:
public class Pages {
public static final String FOO_URL "foo/foo.action"
public static final String FOO_VIEW "test/foo"
public static final String BAR_URL "bar/bar.action"
public static final String BAR_VIEW "test/bar"
}
then inside your controller you'd reference them like this:
#RequestMapping(value=Pages.FOO_URL, method=RequestMethod.GET)
public String handleFoo(Model model) {
return Pages.FOO_VIEW;
}
They're easy to change as they're all in one place.
You say you'd like to avoid hard-coding paths throughout the application, but typically all the controllers (and thus all the url mappings) reside in one directory. For example if you have a maven structure they'll be someplace like src/main/java/com/mycompany/myapp/web/controllers/. Do you envision yourself ever asking the question, "Just where did I put the url mapping for the /myapp/v1/search endpoint?", and not being able to figure out that it's in /src/main/java/com/mycompany/myapp/web/controllers/V1SearchController.java?
Also once you choose the urls they're pretty much fixed since they represent an interface with clients, and changing them probably means breaking backward compatibility.
Not that I think a class with a bunch of static final Strings is all that bad, I just think it's mostly unnecessary.
Related
I need to implement a solution as part of Test framework & I am considering singleton pattern for reasons explained below. However, I am not able to achieve my intended solution & therefore would need some suggestions/inputs on possible implementations.
Problem Statement :
I have a environment (env of the product I am testing) configuration properties file which I want to load & make the value of the parameters accessible globally to the test framework.
I figured using the singleton pattern because these properties are one-time values (should report an exception if tried to initialize more than once), should be available globally & have an one-point access to the methods.
However, the list of properties/parameters is really long & therefore it's wise to break it into modules (classes). For the below explanation, I tried with composition.
For e.g.
public class Configuration {
private static Configuration configObj;
private static Database dbDetails;
private static Machine macDetails;
//...
//... many more modules
public static synchronized void createInstance(Properities envProps){
//Should create only one instance of Configuration
// and should also initialize Database & Machine objects.
}
public static Configuration getConfigObject(){
return configObj;
}
}
public class Database {
private static String dbConnectString;
public Database(String dbcs){
dbConnectString = dbcs;
}
public static String getDbConnectString(){
return dbConnectString;
}
}
public class Machine {
private static String hostname;
private static String loginUsername;
public Machine(String hostname,String loginUsername){
this.hostname = hostname; //It may include some trimming/cleaning
this.loginUsername = loginUsername;
}
public static String getHostName(){
return hostname;
}
}
PS: Just a sample typed-in code for the understanding of my problem statement.
Expectation : The expectation now is that when trying to get the hostname, I should have a single point of access via Configuration static object (assuming that I have initialized all member variables successfully) i.e.
String hostname = Configuration.getHostname();
OR
String hostname = Configuration.getConfigObject().getHostname();
Current Issue :
How to create one static object that will refer to all methods using either composition or inheritance (Conceptually, composition would be the right approach).
Multiple Inheritance would have solved the issue but Java doesn't support so ruled out. Cannot consider Interfaces either because overriding all methods is tedious & lengthy & the parameters/methods will keep changing over-time.
All suggestions are welcome even if it requires to scrap this design pattern & try something different.
You will not be able to "automatically" delegate static calls to modules. And even if the calls were not static, as you stated, Java does not support multiple inheritance.
Option 1:
Have your main Configuration class provide static methods that return instances to your modules. Whenever you want to read a configuration entry, first get the module instance, then query the entry itself:
Configuration.getDatabaseConfiguration().getServerName();
This method has the advantage that it is very clear which part of your configuration you are referring to. If you would just use Configuration.getServerName(), you cannot distingish whether you want to retrieve the database's server name, or the webserver's.
Option 2:
If you are able to use Java 8 and your configuration is large, but very simple (statically known at compile time or extractable from very few instances), you could consider using the new default interface methods (https://blog.idrsolutions.com/2015/01/java-8-default-methods-explained-5-minutes/).
You would then create an interface for each module, where all getters have default implementations. Your main configuration class would implement all the module interfaces without overriding any of the methods. This way all configuration entries can be queried from one object, but you still have to obtain this object by a static method. This is as close to multiple inheritance as you can get. I would definitely recommend option 1 though.
How do you set variables which contain the class name, like TAG in android.util.Log, while respecting Dont-Repeat-Yourself?
These are some possibilities:
In Google code, it is often used like
public class Classname {
public final String TAG = "Classname";
which repeats the classname and was not refactor-renamed correctly in AndroidStudio (no Strings were).
Then, there is a dynamic variant
public class Classname {
public final String TAG = getClass().getName();
which does not repeat the Classname, thus seems better, yet is less readable.
Or, you could make TAG static (this might be premature optimization). Apart from the official version above, you could get the name in code like
public class Classname {
public final static String TAG
= new Object() { }.getClass().getEnclosingClass().getName();
which is way less readable, and does have problems with inheritance (being static).
What is the best practice concerning this?
Is there a better way than 1-3? (Or is this a wrong approach?)
I have gone with the dynamic approach in the past:
public class Classname {
public final String TAG = getClass().getName();
It is not that unreadable, and it is self-contained.
For more complex cases of DRY-ness, there is always the possibility of creating your own annotations, and then either
Use a two-step compile process to first generate non-DRY sources and then compile them into non-DRY .class files.
Use the annotations in an initialization step within your program to fill in the non-DRY parts at run-time, before running any logic that depends on those parts.
Using the second approach, you could have something like
#ReplaceWithClassName("TAG")
public class Classname {
public final String TAG;
And then you would iterate through all classes annotated with #ReplaceWithClassName filling in the blanks as an initialization step (more on iterating through annotated classes here; more on changing a final String here).
Annotations, introspection and code-generation provide great flexibility and power. Therefore, use wisely if you use them at all. For this particular case, the "dynamic approach" is much more readable.
retrieve class name dynamically
#JeffMiller gave the example in the ClassLogger class of his sormula project. In the class Logger, he uses
StackTraceElement[] stes = new Throwable().getStackTrace();
int e = stes.length - 1;
for (int i = 0; i < e; ++i) {
if (stes[i].getClassName().equals(classLoggerClassName)) {
// next on stack is the class that created me
log = LoggerFactory.getLogger(stes[i + 1].getClassName());
break;
}
}
to get the caller's class name.
use the class to get its name
#FlorentBayle said in the comments that
public final static String TAG = Classname.class.getName();
should be refactored correctly. (And is more readable than variant 3 above).
This is also the approach used by third-party logging frameworks like SLF4J. It is initialized via
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
I have a bunch of constants throughout my code for various adjustable properties of my system. I'm moving all of them to a central .properties file. My current solution is to have a single Properties.java which statically loads the .properties file and exposes various getter methods like this:
public class Properties {
private static final String FILE_NAME = "myfile.properties";
private static final java.util.Properties props;
static {
InputStream in = Properties.class.getClassLoader().getResourceAsStream(
FILE_NAME);
props = new java.util.Properties();
try {
props.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String getString(Class<?> cls, String key) {
return props.getProperty(cls.getName() + '.' + key);
}
public static int getInteger(Class<?> cls, String key) {
return Integer.parseInt(getString(cls, key));
}
public static double getDouble(Class<?> cls, String key) {
return Double.parseDouble(getString(cls, key));
}
}
The only problem with that is that for every constant that I get from this file, I have some boilerplate:
private final static int MY_CONSTANT = Properties.getInteger(
ThisClass.class, "MY_CONSTANT");
I don't think I want to use Spring or the like as that seems like even more boilerplae. I was hoping to use a custom annotation to solve the issue. I found this tutorial, but I can't really sort out how to get the functionality that I want out of the annotation processing. The Java docs were even less helpful. This should be a thing I should be able to do at compile time, though. I know the names of the class and field.
What I'm thinking is something like this:
#MyAnnotation
private static final int MY_CONSTANT;
Anyone know how I would go about doing this or at least best practices for what I want to do?
First of all, you shouldn't do it. It's practical, but too hacky and if you ever want to write a test using different settings, you'll run into problems. Moreover, nobody's gonna understand how it works.
An annotation processor can probably do nothing for you. A Lombok-style-hacking processor can. You want to make
#MyAnnotation
private static final int MY_CONSTANT;
work like
private final static int MY_CONSTANT =
Properties.getInteger(ThisClass.class, "MY_CONSTANT");
The original expression doesn't compile (due to the uninitialized final variable), but it parses fine and Lombok can do its job. There's already something related there:
#Value changes the modifiers to final private
#UtilityClass makes all fields static
So actually, you could write just
#MyAnnotation
int MY_CONSTANT;
and let your annotation change also the modifiers. I'd look at the eclipse and javac handlers for #UtilityClass, I guess all you need is to generate the initializer (which is quite some work because it's all damn complicated).
I don't think Lombok itself will implement this anytime soon, since
all the static stuff is non-testable and mostly bad style
and not everyone wants this in their code
it's not that much boilerplate
it also magically refers to the class Properties, but this could be solved via configuration
but I guess a contribution might be accepted.
Actually not quite clear why and what do you want to archive.
As I correctly undestand, you want use special kind of annotations to automatically assign values for static final constants from some properties file. Unfortunatelly it is impossible without special hacks. And annotations have nothing to do with this.
The reason is that final fields must be initialized and it is compiler's request. There aren't special annotations in java which will provide such syntactic sugar which you want.
But if you insist on this there are two ways:
Extrim way. Init all properties field with default value. Then using this hack in some static init section initialize this value using reflection mechanism and you code via reading values from properties.
Less extrim way: refuse request of final modifiers for properties fields, and using only reflection fill these fields values.
And additionally, for these ways, yes you can use annotations. But you will have to solve following technical issues:
1) Find all fields in all classes in classpath, which are annotated with you special annotation. Look at:
Get all of the Classes in the Classpath and Get list of fields with annotation, by using reflection
2) Force your Properties class to be initialized in all possible enter points of your application. In static section in this class you will load your properties file, and then using (1) method with reflection and classloader, assign values to all constants.
Background: I'm using Google Guice and so it's easier to pass through the configuration class but I think this is not the best way.
I have a configuration class which stores some paths:
class Configuration{
String getHomePath();
String getUserPath();
}
Also I have a class "a" which needs the "homepath" and a class "b" which needs the "userpath".
Is it better to pass the configuration class through the constructor of class a and b or only pass through the specific path?
If you're really using Guice correctly all your configuration like this should appear in modules' configure method. So:
Remove the configuration class.
Create annotation classes, probably called HomePath and UserPath.
Where class a uses getHomePath() replace that with a String field member named homePath.
Where class b uses getUserPath() replace that with a String field member named userPath.
Modify the class a and b constructors to be #Inject annotated (should already be) and take in a String parameter, respectively annotated with #HomePath and #UserPath and assign the String field member that injected value.
Create bindings in your module's configure method use .annotatedWith() which define correct values; if they're only available at run time, bind a provider.
E.G.
class a {
private String homePath;
#Inject
public a(#HomePath String homePath) {
this.homePath = homePath;
}
public String tellMeAboutHome() {
return "We live in a nice home called " + homePath;
}
}
class customModule extends AbstractModule {
public static final String userPath = "/home/rafael";
public void configure() {
bind(String.class).annotatedWith(HomePath.class).to("/home/");
bind(String.class).annotatedWith(UserPath.class).to(userPath);
}
}
If creating annotations is too much work for you, use the #Named annotation Guice ships with.
There's no single answer to your question, there are only options to choose from, based on your specific situation.
If you know your Configuration class is going to grow AND if it's likely for your A and B classes will use more from it, then pass the whole Configuration object to their constructors. NB: I know this is against the YAGNI principle but sometimes you may know you're gonna need it ;-)
Otherwise, you can consider using #Named injection of your paths so that you reduce A and B classes dependencies to their minimum, which is a good design practice.
The general rule is code to make the dependency graph (which classes know about or depend on other classes/ interfaces) as simple, regular and fixed as possible.
If not passing the Configuration class makes a or b have zero dependencies on on user-written classes, or is necessary to avoid a dependency loop, then use the individual path strings. Otherwise, if it makes more sense to say 'this class has access to configuration info, in a way that may change in the future', pass the class.
I'd avoid the singleton approach, especially if you already have Guice set up.
Forgive me if I am asking an obvious question (maybe I missed it in the docs somewhere?) but has anyone found a good way to organize their URLs in Jersey Java framework?
I mean organizing them centrally in your Java source code, so that you can be sure there are not two classes that refer to the same Url.
For example django has a really nice regex-based matching.
I was thinking of doing something like an enum:
enum Urls{
CARS ("cars"),
CAR_INFO ("car", "{info}");
public Urls(String path, String args)
...
}
but you can imagine that gets out of hand pretty quickly if you have urls like:
cars/1/wheels/3
where you need multiple path-ids interleaved with one another...
Any tips?
From my experiences with Jersey, when I tried to annotate two places with the same #Path, I had compilation errors and it wouldn't run. This might not always be the case, so the following might help:
You can get an application.wadl file from your Jersey app by simply requesting it from you web resource:
$ curl http://localhost:8080/application.wadl
or if you prefixed your web services under /ws/
$ curl http://localhost:8080/ws/application.wadl
The application.wadl file is an XML file that shows you all of your resources in your running application, as well as what methods you can call on a resource. See the following resource on how this file is laid out.
Well - I assume you have a #Path on each resource? This means you don't have to keep track of URLs across your entire application, rather just within each class - which is relatively easy if you annotate the interface.
Using enums won't work - you can only put contants into an annotation, but using a class holding final static String could work.
public class UrlConst {
public final static RESOURCE_MY_RESOURCE="/resource";
public final static RESOURCE_MY_RESOURCE2="/resource";
public final static OP_GET_ALL="/";
public final static OP_GET_BY_ID="/{id}";
}
#Path(UrlConst.RESOURCE_MY_RESOURCE)
public interface MyResource {
#GET
#Path(UrlConst.OP_GET_ALL)
#Produces(MediaType.APPLICATION_XML)
public ObjectList getAll();
#GET
#Path(UrlConst.OP_GET_BY_ID)
#Produces(MediaType.APPLICATION_XML)
public Object get(#PathParam("id") int id);
}
#Path(UrlConst.RESOURCE_MY_RESOURCE2)
public interface MyResource2 {
#GET
#Path(UrlConst.OP_GET_ALL)
#Produces(MediaType.APPLICATION_XML)
public ObjectList getAll();
#GET
#Path(UrlConst.OP_GET_BY_ID)
#Produces(MediaType.APPLICATION_XML)
public Object get(#PathParam("id") int id);
}
etc.