How to use enum constant in request mapping annotation? - java

This is as enum of constants.
public enum LoginRequestMappingConstants
{
LOGIN("/login"),
LOGOUT("/logout"),
ADMINISTRATION("/Administration");
private LoginRequestMappingConstants(String requestMapping) {
this.requestMapping = requestMapping;
}
private String requestMapping;
public String getRequestMapping() {
return requestMapping;
}
}
In request mapping annotation I wanted to use the enum of constant.
#RequestMapping(value = LoginRequestMappingConstants.LOGIN.getRequestMapping(), method = RequestMethod.GET)
During compile time only I am getting this error.
The value for annotation attribute RequestMapping.value must be a constant expression. What is meaning of this error ?
What is the correct way to create constants for RequestMapping annotation?

You can't use an enum; you can only use a String. It frequently doesn't make sense to put those paths in a separate place from the controller, but if you do need to, use ordinary constants:
public interface LoginRequestMappings {
String LOGIN = "/login";
String LOGOUT = "/logout";
}
#RequestMapping(LoginRequestMappings.LOGIN)

Related

Call specific method on object depending on selected enum value

Let's assume we have an enum, that represents searchable fields:
enum SearchableFields {
ALL,
FIELD1,
FIELD2,
FIELD3;
}
This enum is displayed via a (combobox) selection inside a GUI. At runtime, I want to evaluate the selection of this combobox and search accordingly.
Depending on the selection, I need to retrieve the fields to search from a POJO (example below) via a getter.
class FieldPojo {
private String field1;
private String field2;
private String field3;
...
public String getField1() {
return field1;
}
...
}
I currently use a switch statement to evaluate the selection of SelectableFields and to then retrieve the correct field(s) to search:
private String retrieveField(FieldPojo f) {
switch (selectedField) {
case ALL:
return retrieveAll(); // method that retrieves all available fields
case FIELD1:
return f.getField1();
...
}
This does work, however I feel like it's clunky.
Question:
Is there a more concise way to do this without evaluating the enum via a switch? (Java 8)
You could store a reference to the getter in your enum constants:
enum SearchableFields {
ALL(FieldPojo::retrieveAll),
FIELD1(FieldPojo::getField1)
private final Function<FieldPojo, String> accessor;
SearchableFields(Function<FieldPojo, String> acccessor) {
this.accessor = accessor;
}
public String get(FieldPojo fp) {
return accessor.apply(fp);
}
}
You can create a static map instead of the switch-case.
private static final Map<SearchableFields,Supplier<String>> searchableFieldsToFieldPojo = Map.of(
ALL, this::retrieveAll,
FIELD1, FieldPojo::retrieveAll
);
And then you can access via:
searchableFieldsToFieldPojo.get(selectedField).get();
Given that you can modify all parts of the code, you have several options:
Put the retrieveField into the class FieldPojo and modify it's parameter so it takes the enum SearchableFields as parameter.
Put the fields of FieldPojo as values into a map with a key of type SearchableFields. You can then decide whether you want to have "ALL" as an extra entry of the map or handle it as special case in a method similar to retrieveField. You could use this to have a "default" handling if you want to update the enum but not the FieldPojo class.
You put retrieveField into the class FieldPojo together with the SearchableFields enum - since only FieldPojo knows, which fields it actually provides as searchable fields.
You use introspection to gather the list of possible searchable fields and also access their contents.
Depending on your real requirements (you only showed a very abstract and specific version of them) one or the other method might be "the right one" for you. I would actually prefer the "everything into FieldPojo" as the most robust one, but on the other hand if you are not able to change FieldPojo and have to handle many different classes like it, the introspection variant might be the right one. (Be aware that it is fragile in terms of security and also probably very slow.)
Enums can contain method definitions, so one way is to define the method that retrieves the field name based on the enum value. I assume you have the actual field name stored as a member field also. Then you can override the method for the special ALL value:
enum SearchableFields {
ALL("all") { // all is just a placeholder in this case
#Override
String retrieveField(FieldPojo f) {
// logic for all fields
}
},
FIELD1("field1"),
FIELD2("field2"),
FIELD3("field3");
SearchableFields(String fieldName) {
this.fieldName = Optional.of(fieldName);
}
SearchableFields() {
fieldName = Optional.empty();
}
private final Optional<String> fieldName;
String retrieveField(FieldPojo f) {
if (fieldName.isPresent()) {
return (String) f.getClass().getField(fieldName.get()).get(f);
} else {
// ...
}
}
}

API-method can return different types, how do i define the return type?

I have the following API method:
#GetMapping
public ResponseEntity<List<Project>> getProjects(#RequestParam(required = false) String userName, #RequestParam(required = false) boolean additionalInfo) {
return ResponseEntity.ok(projectService.getProjects(userName, additionalInfo));
}
It currently returns ResponseEntity<List<Project>>. But if the optional paramater additionalInfo is true, i would like to return ResponseEntity<List<ProjectAdditionalInfoDTO>>. How do i define the return type to indicate that both of them can be returned? Of course i could use ResponseEntity<?>, but that would be ugly.
I'd keep things simple and just split things up into two separate controller methods... e.g.
#GetMapping
public ResponseEntity<List<Project>> getProjects(#RequestParam(required=false) String userName) {
//...
}
#GetMapping
public ResponseEntity<List<ProjectAdditionalInfoDTO>> getProjectsWithAdditionalInfos(#RequestParam(required=false) String userName, #RequestParam(required=true) boolean additionalInfo) {
//...
}
If they both have the same interface (let's say BaseProject) you can make it return the following:
ResponseEntity<List<? extends BaseProject>>
There is no possibility to show that 2 options are possible in the return type via the method signature.
As far as I can understand ProjectAdditionalInfoDTO should inherit Project. That means that if you add inheritance there, then you can return the parent class since ProjectAdditionalInfoDTO would always be Project. If not, then since they are different resources you should have different endpoints to access them.

How to use the getter method which is stored in mongodb for some other POJO class?

I am having one class which is having getter and setter methods i am storing that getter method in mongodb with some other collection. After getting the method name from DB how to access that method. Whether it is possible to do like this or not?
public class MappingAlgorithmScoreGenerationRules {
#Field(value = FieldNames.CATEGORY)
private String category;
#Field(value = FieldNames.ATTRIBUTE_NAME)
private MappingScoreGenerationLogic attributeName;
#Field(value = FieldNames.PRIORITY)
private Integer priority;
#Field(value = FieldNames.ATTRIBUTE_SCORE)
private Integer attributeScore;
#Field(value = FieldNames.FINAL_THRESHOLD)
private Integer finalThreshold;
#Field(value = FieldNames.RESULT_COUNT)
private Integer resultCount;
#Field(value = FieldNames.NORMALIZED_VALUE)
private Integer normalizedValue;
#Field(value = FieldNames.GETTER_METHOD)
private String getterMethod;
}
This is the class where i am storing the method name.
public class MatchEntry {
private double matchedWeight;
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
getMatchedWeight is the method name i am going to store in the DB MappingAlgorithmScoreGenerationRules.
After getting the method name how to access the method name?
I want to access like
For example: MatchEntry.(the value get from db)
Use reflection API - https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
Method methodToInvoke
= MatchEntry.class.getMethod("methodName", methodParams,..);
methodToInvoke.invoke(matchEntryInstance, params,..);
In Java you can achieve method access by name using reflection (https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html).
This is a tutorial you may be able to use to lean more about this language feature: https://www.geeksforgeeks.org/reflection-in-java/
In your example, let's say you have loaded an instance of MappingAlgorithmScoreGenerationRules from the database, whose getterMethod attribute returns "getMatchedWeight".
Let's also assume that you have an instance of MatchEntry.
You would then access as follows:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String getterMethodName = rules.getGetterMethod();
Method getter = MatchEntry.class.getMethod(getterMethodName);
Object value = getter.invoke(entry);
This code snippet omits Exceptions, in particular NoSuchMethodException and InvocationTargetException.
Please note that if you choose this approach, and depending heavily on the rest of your domain model, you will also need to be very careful with assumptions about the return type of the actual value (unless you can somehow guarantee that they are all the same, in which case you could cast the value).
Code that uses reflection is also inherently brittle and prone to failure as soon as you refactor. Imagine you have a populated database with these rules, and during a code review a couple of methods are renamed. Inoccuous change? Or will your entire setup break on the next deploy?
A (type-)safer approach might be to ensure all entries and related objects derive from an interface that standardises the return type on a getValue(String attributeName) method, so instead of messing with reflection you might do:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String attributeName = rules.getAttribute(); //instead of 'getterMethod'
Object value = entry.getValue(attributeName);
where MatchEntry.getValue might be defined as:
public Object getValue(String attribute) {
switch(attribute) {
case "matchedWeight": return getMatchedWeight();
default: return null; //or you could throw an exception
}
}
This would easily survive any kind of method name refactoring and reorganisation, but adds the overhead of adding a case to the switch for every new attribute.
This problem could be partially solved with a runtime annotation that essentially binds an attribute name to a getter method, e.g.:
public class MatchEntry implements Matchable {
private double matchedWeight;
#MyCustomAnnotation("matchedWeight")
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
public interface Matchable {
default Object getValue(String attributeName) {
//read methods annotated with 'MyCustomAnnotation's in current class and call the one with matching value
}
}
Your getValue(String attributeName) would be tasked with reading these annotations and dynamically figuring out which getter to call. Still requires the annotation to be added everywhere it's needed, but at least it's with the getter and not hidden in some switch that's potentially duplicated across multiple class definitions.
Instead you just need a single default definition in the parent interface, as hinted above.

java jersey 2 how to process regular html form array with post?

I have a jersey endpoint
#Path(value = "/testfields")
#POST
#Consumes({"application/x-www-form-urlencoded"})
public Response acceptFields(#BeanParam MyWrapper initialWrapper,String entity) {
//.......
}
MyWrapper is:
class MyWrapper{
#FormParam("param1")
private String param1;
#FormParam("inners")
private List<MyInnerWrapper> inners;
//..getters setters
}
class MyInnerWrapper{
#FormParam("innerParam1")
private String innerParam1;
//.... getters setters
}
I have request POST entity string:
param1=aaa&inners[0]["innerParam"]=bbb&inners[1]["innerParam"]=nnn
The issue is I can obtain parent`s field param1 with #BeanParam annotation, but I can't obtain inner list of custom classes, why? How to process regular html form array? I need to get my class evaluated with its inner classes in my endpoint. I tried array, list of objects, nothing works. Thanks
AFAIK, that type of syntax is not supported in Jersey. If you want to use custom types for #FormParam, then you need to meet the requirements of at least one those listed in the Javadoc. One options is to just have a constructor with a String argument. For example
public class MyInnerWrapper {
private final String innerParam;
public MyInnerWrapper(String param) {
this.innerParam = param;
}
public String getInnerParam() {
return innerParam;
}
}
Then all you need to do is send this request
param1=blahparam&inners=first&inners=second&inners=third
Then you can have
#FormParam("inners")
private List<MyInnerWrapper> inners;
There's no need for an [] to specify indices. Duplicates are allowed. That's why we are allowed to have lists and arrays for the #FormParam types.
Now if you want to have more than one property and then try to map them like you currently are, I don't think that will work. At least not in Jersey. I would recommend maybe looking into using JSON if you need more complex types. Otherwise just stick to simple keys.

How to inject String constants easily with Weld?

We have a situation where we provide an external configuration in form of a Map to our running programs. I have found that JSR-330 Dependency Injection gives a much cleaner way to use that configuration map in the code instead of passing the map around or to use JNDI to get it.
#Inject #Named("server.username") String username;
lets the JSR-330 implementation fill in this field automatically.
With Guice I can set the value with
bindConstant().annotatedWith(Names.named(key)).to(value);
I would like to be able to do the same in Weld (bind "server.username" to e.g. "foobar") and I understand that the mechanism most likely is beans.xml, but I would prefer a simple "feed this map to Weld, please" code alternative. What would be a good way to do this?
EDIT 2013-10-16: After looking into Dagger which works at compile time and not runtime, I found that with us usually having 10-20 per program we could live with having a #Provider method for each configuration string which then looks up in the configuration map. This allows for method specific behavior (including default values), ability to provide javadoc, and ability to put all these methods in the same class. Also it works well with Weld out of the box. I am considering writing a fuller explanation in a blog entry.
I'd like that bounty now please. Figuring this out taught me quite a bit about the innards of WELD, and here's the most interesting lesson: #Named is a qualifier, and must be treated as such if you are going to be able to match against it.
I do have a warning for you: If you are missing any values in your app, it will fail at deploy or load time. This may be desirable for you, but it does specifically mean that "default" values are not possible.
The injection point is specified exactly as you have above, and here's the extension code needed to make it work:
#ApplicationScoped
public class PerformSetup implements Extension {
Map<String, String> configMap;
public PerformSetup() {
configMap = new HashMap<String, String>();
// This is a dummy initialization, do something constructive here
configMap.put("string.value", "This is a test value");
}
// Add the ConfigMap values to the global bean scope
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd, BeanManager bm) {
// Loop through each entry registering the strings.
for (Entry<String, String> configEntry : configMap.entrySet()) {
final String configKey = configEntry.getKey();
final String configValue = configEntry.getValue();
AnnotatedType<String> at = bm.createAnnotatedType(String.class);
final InjectionTarget<String> it = bm.createInjectionTarget(at);
/**
* All of this is necessary so WELD knows where to find the string,
* what it's named, and what scope (singleton) it is.
*/
Bean<String> si = new Bean<String>() {
public Set<Type> getTypes() {
Set<Type> types = new HashSet<Type>();
types.add(String.class);
types.add(Object.class);
return types;
}
public Set<Annotation> getQualifiers() {
Set<Annotation> qualifiers = new HashSet<Annotation>();
qualifiers.add(new NamedAnnotationImpl(configKey));
return qualifiers;
}
public Class<? extends Annotation> getScope() {
return Singleton.class;
}
public String getName() {
return configKey;
}
public Set<Class<? extends Annotation>> getStereotypes() {
return Collections.EMPTY_SET;
}
public Class<?> getBeanClass() {
return String.class;
}
public boolean isAlternative() {
return false;
}
public boolean isNullable() {
return false;
}
public Set<InjectionPoint> getInjectionPoints() {
return it.getInjectionPoints();
}
#Override
public String create(CreationalContext<String> ctx) {
return configValue;
}
#Override
public void destroy(String instance,
CreationalContext<String> ctx) {
// Strings can't be destroyed, so don't do anything
}
};
abd.addBean(si);
}
}
/**
* This is just so we can create a #Named annotation at runtime.
*/
class NamedAnnotationImpl extends AnnotationLiteral<Named> implements Named {
final String nameValue;
NamedAnnotationImpl(String nameValue) {
this.nameValue = nameValue;
}
public String value() {
return nameValue;
}
}
}
I tested that this worked by making a WELD-SE app:
#ApplicationScoped
public class App {
#Inject
#Parameters
List<String> parameters;
#Inject
#Named("string.value")
String stringValue;
public void printHello(#Observes ContainerInitialized event) {
System.out.println("String Value is " + stringValue);
}
}
Lastly, don't forget /META-INF/services/javax.enterprise.inject.spi.Extension, replacing weldtest with the classpath you use:
weldtest.PerformSetup
That should make all of this work. Let me know if you run into any difficulties and I'll send you my test project.
Not all that interested in the bounty, but I'll take it if it's still on the table. This is VERY similar to some code I'm using at $DAYJOB, and so this isn't theory, it's what I use in production code, but modified to protect the guilty. I haven't tried compiling the modified code, so be warned that I may have made some errors in changing names and such, but the principles involved here have all been tested and work.
First, you need a Value Holder Qualifier. Use #Nonbinding to keep WELD from matching ONLY to qualifiers with identical values, since we want all values of this particular qualifier to match a single injection point. By keeping the qualifier and value in the same annotation, you can't just "forget" one of them by accident. (KISS principle)
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface ConfigValue {
// Excludes this value from being considered for injection point matching
#Nonbinding
// Avoid specifying a default value, since it can encourage programmer error.
// We WANT a value every time.
String value();
}
Next, you need a producer method which knows how to get the Map. You should probably have a Named bean which holds the producer method, so you can either explicitly initialize the value by using getters/setters, or else have the bean initialize it for you.
We must specify a blank value for the qualifier on the producer method to avoid compile time errors, but it's never used in practice.
#Named
public class ConfigProducer {
//#Inject // Initialize this parameter somehow
Map<String,String> configurationMap;
#PostConstructor
public void doInit() {
// TODO: Get the configuration map here if it needs explicit initialization
}
// In general, I would discourage using this method, since it can be difficult to control exactly the order in which beans initialize at runtime.
public void setConfigurationMap(Map<String,String> configurationMap) {
this.configurationMap = configurationMap;
}
#Produces
#ConfigValue("")
#Dependent
public String configValueProducer(InjectionPoint ip) {
// We know this annotation WILL be present as WELD won't call us otherwise, so no null checking is required.
ConfigValue configValue = ip.getAnnotated().getAnnotation(ConfigValue.class);
// This could potentially return a null, so the function is annotated #Dependent to avoid a WELD error.
return configurationMap.get(configValue.value());
}
}
Usage is simple:
#Inject
#ConfigValue("some.map.key.here")
String someConfigValue;
It may be possible to implement this as an #Dependent Producer method that itself injects an #InjectionPoint which would allow you to reflect upon the field you're being injected into -- this would let you peek into a custom annotation (not a qualifier) member on the field to figure out the val you want to return
#Inject #ConfigMapQualifier #Val("user.name") String user;
...
#Produces #ConfigMapQualifier configProducr(...) {
...
#Inject InjectionPoint ip;
// use e.g. ip/getJavaMember() then reflection to figure out the #Val value membr.
Would implementing a custom Weld InjectionServices not be an option here ?
what about
#Resource(name = "server.username", type = java.lang.String.class)
private String injectTo;
Javadoc: http://download.oracle.com/javase/6/docs/api/javax/annotation/Resource.html

Categories