Pass a tab as an annotation parameter: "attribute value must be constant" - java

I have a class containing multiple constants and I would like to return all the constants except one in order to make some tests. I have made a simple method but it return the error "attribute value must be constant" when I use it in my annotation.
public final class RolesConstants {
public static final String APP_SYSTEM = "APP_SYSTEM";
public static final String APP_CLIENT = "APP_CLIENT";
public static final String APP_PROFESSIONAL = "APP_PROFESSIONAL";
public static final String APP_ADMIN = "APP_ADMIN";
public static final String PRO_ADMIN = "PRO_ADMIN";
public static final String PRO_ADD_BOOKING = "PRO_ADD_BOOKING";
public static final String PRO_EDIT_BOOKING = "PRO_EDIT_BOOKING";
...
public static String[] allRolesButAPP_SYSTEM() {
return new String[]{ APP_CLIENT, APP_PROFESSIONAL, ... };
}
}
import org.springframework.security.test.context.support.WithMockUser;
public class ProfessionalResourceIT {
#WithMockUser(roles = {RolesConstants.allRolesButAPP_SYSTEM()})
public void cannotGetIfNotSystem(){
assertThat(...);
}
}
attribute value must be constant

Could you try something like this
import org.springframework.security.test.context.support.WithMockUser;
public class ProfessionalResourceIT {
#WithMockUser(roles = {RolesConstants.APP_SYSTEM, RolesConstants.APP_CLIENT, so on})
public void cannotGetIfNotSystem(){
assertThat(...);
}
}

Related

How can I provide this sort of String builder class?

I like to have a Drive class where all files and folders for a project are managed.
My first attempt was pretty easy like a lot of functions (most of them with arguments).
Now I try to make it more fancy because it became more and more annoying to have a lot of functions, in which the desired one can be found. To not have an XY-problem here, I start with my dream.
I like to construct the Drive class in a way, so that it is super easy to find a certain file or folder.
If you look in the main function, I can find every needed file by writing a point and look which subclasses/methods are proposed to continue, till I find it and add .str to it. At every point, only the subclasses/methods will be proposed which makes sense at this point.
It almost works! It is more complicated to write and maintain as the first approach, but If I use it very often, it could be worth it.
I can:
go into subfolders
go into subfolders with name inside the argument
But there is an error if I define a fixed-name-subfolder of a fluid-name-folder like in the code below.
Now my questions:
how can I change the code so the main Function doesn't show this error?
would you recommend a completely different approach to the "make it easy to find strings inside a huge list of strings via making collections inside collections... of strings"-problem?
package utilities;
public class Drive_draft {
private static final String fs = System.getProperty("file.separator");
public static final String str = System.getProperty("user.home").concat(fs);
public static class IeCreation {
public static final String str = Drive_draft.str.concat(".meetings").concat(fs);
public static class Abstract {
public static final String str = IeCreation.str.concat("Abstracts").concat(fs);
}
public static class Meeting {
public static final String str = IeCreation.str.concat("Ueberordnungen").concat(fs);
}
}
public static class MetsSIPs {
public static final String str = Drive_draft.str.concat("workspace").concat(fs).concat("metsSIPs").concat(fs);
public static class preSIPs {
public static final String str = MetsSIPs.str.concat("preSIPs").concat(fs);
}
public static class RosettaInstance {
private static class MaterialflowId {
public static String str;
private static class ProducerId {
public static String str;
private static class Abstract {
public static String str;
public static class Mets {
public static final String str = Abstract.str.concat("content").concat(fs).concat("ie1.xml");
}
}
private static class Meeting {
public static String str;
}
public static Abstract Abstract (String value) {
Abstract ret = new Abstract();
ProducerId.Abstract.str = str.concat(value).concat(fs);
return ret;
}
public static Meeting Meeting (String value) {
Meeting ret = new Meeting();
ProducerId.Meeting.str = str.concat(value).concat(fs);
return ret;
}
}
public static ProducerId ProducerId (String value) {
ProducerId ret = new ProducerId();
MaterialflowId.ProducerId.str = str.concat(value).concat(fs);
return ret;
}
}
public static MaterialflowId MaterialflowId (String value) {
MaterialflowId ret = new MaterialflowId();
MaterialflowId.str = str.concat(value).concat(fs);
return ret;
}
}
public static class Dev extends RosettaInstance {
public static final String str = MetsSIPs.str.concat("dev").concat(fs);
}
public static class Test extends RosettaInstance {
public static final String str = MetsSIPs.str.concat("test").concat(fs);
}
public static class Prod extends RosettaInstance{
public static final String str = MetsSIPs.str.concat("prod").concat(fs);
}
}
#SuppressWarnings("static-access")
public static void main(String[] args) {
System.out.println(Drive_draft.MetsSIPs.Dev.str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("2").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Meeting("oast").str);
System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").Mets.str); //Error: Mets cannot be resolved or is not a field
}
}
You can encode your "directory" structure with interfaces, with each interface declaring what the user can do next. Then the implementation can use a StringBuilder to just append the appropriate snippets and keep returning this.
// PathBuilderInterfaces.java
public class PathBuilderInterfaces {
public interface Buildable {
String build();
}
public interface Drive extends Buildable {
IeCreation ieCreation();
MetsSIPs metsSIPs();
}
public interface IeCreation extends Buildable {
String ieCreationAbstract();
String meeting();
}
public interface MetsSIPs extends Buildable {
RosettaInstance dev();
RosettaInstance test();
RosettaInstance prod();
}
public interface RosettaInstance extends Buildable {
MaterialFlowId materialFlowId(String value);
}
public interface MaterialFlowId extends Buildable {
ProducerId producerId(String value);
}
public interface ProducerId extends Buildable {
Abstract producerIdAbstract(String value);
String meeting(String value);
}
public interface Abstract extends Buildable {
String mets();
}
}
// PathBuilder.java
import static com.example.somepackage.PathBuilderInterfaces.*;
public class PathBuilder implements Drive, IeCreation, MetsSIPs, RosettaInstance, MaterialFlowId, ProducerId, Abstract{
private StringBuilder builder = new StringBuilder(str);
private static final String fs = System.getProperty("file.separator");
public static final String str = System.getProperty("user.home").concat(fs);
public static Drive drive() {
return new PathBuilder();
}
#Override
public String build() {
return builder.toString();
}
#Override
public IeCreation ieCreation() {
builder.append(".meetings").append(fs);
return this;
}
#Override
public MetsSIPs metsSIPs() {
builder.append("workspace").append(fs).append("metsSIPs").append(fs);
return this;
}
#Override
public RosettaInstance dev() {
builder.append("dev").append(fs);
return this;
}
#Override
public RosettaInstance test() {
builder.append("test").append(fs);
return this;
}
#Override
public RosettaInstance prod() {
builder.append("prod").append(fs);
return this;
}
#Override
public MaterialFlowId materialFlowId(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public ProducerId producerId(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public Abstract producerIdAbstract(String value) {
builder.append(value).append(fs);
return this;
}
#Override
public String meeting(String value) {
builder.append(value).append(fs);
return build();
}
#Override
public String mets() {
builder.append("content").append(fs).append("ie1.xml");
return build();
}
#Override
public String ieCreationAbstract() {
builder.append("Abstracts").append(fs);
return build();
}
#Override
public String meeting() {
builder.append("Ueberordnungen").append(fs);
return build();
}
}
Usage:
// in a main method somewhere
System.out.println(
PathBuilder.drive()
.metsSIPs()
.dev()
.materialFlowId("1")
.producerId("t")
.producerIdAbstract("est")
.mets());

Inject value into a static field

Here is my class:
public class DeduplicationErrorMetric extends AbstractErrorMetric {
public static final String DEDUPLICATIONS_METRIC = "deduplications";
public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";
private static String DEDUPLICATION_TOPIC_NAME;
private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
private static final List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", DEDUPLICATION_TOPIC_NAME),
Tag.of("action", "send"), Tag.of("result", "failure"));
public DeduplicationErrorMetric() {
super(Map.of(
DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
));
}
#Override
public void incrementMetric(String key) {
errorCounters.get(key).increment();
}
}
I have #Value("${kafka.topic.deduplication}") in my application.yml, and I need to insert the value into DEDUPLICATION_TOPIC_NAME before the bean will be created. How can I do it?
You can use the setter to do this but I'd advocate against this practice !
This means your field will be null before a first instance comes and invokes this injection point
Your static field is not final so can lead to modification, thus lead to hard to debug bugs
It will not solve your current problem as the null value will be used in this case for KAFKA_ERROR_TAGS
#Value("${kafka.topic.deduplication}")
private void setDeduplicationTopicName(String deduplicationTopicName) {
this.DEDUPLICATION_TOPIC_NAME = deducplicationTopicName;
}
Instead, maybe try to create a #Singleton bean and use #Value on its fields, then you're sure you have only one instance.
For your list, you can then use #PostConstruct to make sure it's instantiated once
What you could do here is to directly use injection from a properties file.
If it is a SpringBoot app, in you application properties set your kafka.topic.deduplication property (you can have different values for different environments).
This way, Spring will get the value while constructing the bean.
Your code could look something like this:
public class DeduplicationErrorMetric extends AbstractErrorMetric {
public static final String DEDUPLICATIONS_METRIC = "deduplications";
public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";
private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
private static final List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", deduplicationTopicName),
Tag.of("action", "send"), Tag.of("result", "failure"));
#Value("${kafka.topic.deduplication}")
private String deduplicationTopicName;
public DeduplicationErrorMetric() {
super(Map.of(
DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
));
}
#Override
public void incrementMetric(String key) {
errorCounters.get(key).increment();
}
}
Remove the keyword "static" and then you will be able to change it in the instance.
Static means that the field is locked to the class.
public class DeduplicationErrorMetric extends AbstractErrorMetric {
public static final String DEDUPLICATIONS_METRIC = "deduplications";
public static final String KAFKA_MESSAGES_METRIC = "kafka.messages";
private String DEDUPLICATION_TOPIC_NAME;
private static final List<Tag> DEDUPLICATION_ERROR_TAGS = List.of(Tag.of("type", "failed"));
private List<Tag> KAFKA_ERROR_TAGS = List.of(Tag.of("topic", DEDUPLICATION_TOPIC_NAME),
Tag.of("action", "send"), Tag.of("result", "failure"));
public DeduplicationErrorMetric() {
super(Map.of(
DEDUPLICATIONS_METRIC, DEDUPLICATION_ERROR_TAGS,
KAFKA_MESSAGES_METRIC, KAFKA_ERROR_TAGS
));
}
#Override
public void incrementMetric(String key) {
errorCounters.get(key).increment();
}
public void setTopic(String value){
DEDUPLICATION_TOPIC_NAME = value;
}
}
private void example(){
DeduplicationErrorMetric dem = new DeduplicationErrorMetric();
//Set the instance value directly
dem.DEDUPLICATION_TOPIC_NAME = "Test";
//Set via a function, potentially with other variables.
demo.setTopic("Test");
}
I would also recommend making the variable name lowercase now that it is not static, as good coding practice.

Java: Using Supplier to pass in values at runtime

The problem I am trying to solve is described in OO: dependent class needs information from grandparent class
import java.util.function.Supplier;
public class SupplyMe {
private Supplier<String> supplied;
public SupplyMe(Supplier<String> supplied) {
this.supplied = supplied;
}
public void printSupplied() {
System.out.println(supplied.get());
}
public static void main(String[] args) {
String changingStr = "hi";
Supplier<String> helloStrSupplier = () -> changingStr;
SupplyMe mySupplyMe = new SupplyMe(helloStrSupplier);
mySupplyMe.printSupplied();
changingStr = "hi2";
mySupplyMe.printSupplied();
}
}
the following code is throwing
SupplyMe.java:18: error: local variables referenced from a lambda expression must be final or effectively final
Supplier<String> helloStrSupplier = () -> changingStr;
What can I do to make Supplier be able to supple the value at runtime?
i was able to get it work by doing this
import java.util.function.Supplier;
public class SupplyMe {
public static String changingStr = "";
private Supplier<String> supplied;
public SupplyMe(Supplier<String> supplied) {
this.supplied = supplied;
}
public void printSupplied() {
System.out.println(supplied.get());
}
public static void main(String[] args) {
changingStr = "hi";
//Supplier<String> helloStrSupplier = changingStr;
Supplier<String> helloStrSupplier = new DynamicSupplier();
SupplyMe mySupplyMe = new SupplyMe(helloStrSupplier);
mySupplyMe.printSupplied();
changingStr = "hi2";
mySupplyMe.printSupplied();
}
static class DynamicSupplier implements Supplier<String> {
#Override
public String get() {
return changingStr;
}
}
}

How to provide parameters to a class with static methods without changing the static qualifier on them?

I have a class with static methods:
public class CompletelyStatic {
public final static String PARAM = "abc";
public static String doSomethingSpecial() {
return "qqq" + PARAM;
}
}
These methods are used everywere throughout the code. The new requirement is to load PARAM value from external config. This config is provided via Config object, through dependency injection, i.e.
public class CompletelyStatic {
#Inject
private Config configProvider;
public final static String DEFAULT_PARAM = "abc";
public String doSomethingSpecial() {
return "qqq" + configProvider.getSpecialParam(DEFAULT_PARAM);
}
}
Unfortunately, here I had to change static qualifier on doSomethingSpecial, so everywhere I used it, I have to inject a CompletelyStatic instance. I'd rather avoid that. I could probably do something like that:
public class CompletelyStatic {
public final static String DEFAULT_PARAM = "abc";
public static String doSomethingSpecial(Config configProvider) {
return "qqq" + configProvider.getSpecialParam(DEFAULT_PARAM);
}
}
But if doSomethingSpecial invoked some private methods underneath, I would have to propagate configProvider along. Is there a better solution?
Edit. If CompletelyStatic had some internal private methods, I should then propagate configProvider to them:
public class CompletelyStatic {
public final static String DEFAULT_PARAM = "abc";
public static String doSomethingSpecial(Config configProvider) {
return "qqq" + otherMethod(configProvider);
}
private static String otherMmethod(Config configProvider) {
return "more logic " + configProvider.getSpecialParam(DEFAULT_PARAM);
}
}
Edit 2. To clarify, I have no influence on the Config object. I know it would be nice if it had static methods, but it doesn't.
You might have to do something like this:
public class CompletelyStatic {
#Inject
private Config configProvider;
// Keep a static private instance of your Static class
private static CompletelyStatic cs = new CompletelyStatic();
//If needed, make the constructor of your class private
private CompletelyStatic(){
}
public final static String DEFAULT_PARAM = "abc";
public static String doSomethingSpecial() {
return "qqq" + cs.getConfigProvider().getSpecialParam(DEFAULT_PARAM);
}
public Config getConfigProvider(){
return configProvider;
}
}
Your other private methods will be able to use the configProvider object in a similar manner: cs.getConfigProvider()
Update
public class CompletelyStatic {
public final static String DEFAULT_PARAM = "abc";
//Keep a static reference to the ConfigProvider object.
private static Config configProvider;
public static String doSomethingSpecial(Config configProvider) {
CompletelyStatic.configProvider = configProvider;
return "qqq" + otherMethod(configProvider);
}
// Here, you will not need to parameterize your other methods.
private static String otherMmethod() {
return "more logic " + configProvider.getSpecialParam(DEFAULT_PARAM);
}
}
Hope this helps!
Usually, the configuration object must be a static
public class CompletelyStatic
{
public final static String DEFAULT_PARAM = "abc";
public static String doSomethingSpecial()
{
return "qqq" + Config.getSpecialParam(DEFAULT_PARAM);
}
}
or
public class CompletelyStatic
{
private static String SPECIAL_PARAM = Config.getSpecialParam(DEFAULT_PARAM);
public final static String DEFAULT_PARAM = "abc";
public static String doSomethingSpecial()
{
return "qqq" + SPECIAL_PARAM;
}
}
or
config should be a singleton instance in that case Config.getInstance().getSpecialParam(DEFAULT_PARAM);
Hope this helps :)
The better solution can be loading static Config variable during application startup through an init() like method as shown in the below code. The advantage of this approach is that you don't need to change/modify all of your dependent classes if you are moving from Config to something else. Otherwise, you need to change all of your classes from where you are invoking doSomethingSpecial().
public class CompletelyStatic {
private static Config configProvider;
//you need to load the below init method during application start up
public static void init(Config configProvider) {
CompletelyStatic.configProvider= configProvider;
}
public static String doSomethingSpecial() {
return "qqq" + otherMethod();
}
private static String otherMmethod() {
return "more logic " + configProvider.getSpecialParam(DEFAULT_PARAM);
}
}
Also, in this approach, the method signature public String doSomethingSpecial() did not change from the original class (so no effect to all of the dependent classes, but only point is to load init during start up).

Is a good practice to use static variables for holding properties from file in a Spring MVC project

The code below is working perfectly but I am in doubt if I am using the best approach for the requirenment: read, from a couple of places, property from a properties file in a Spring project. Basically, I created a public class with static variables. Now I am using Spring 3 plus JDK6. I might upgrade Spring to 4 soon but I will not be able to chnage JDK version.
mvc-dispatcher-servlet.xml
Properties File
url = http://localhost:8080/MHE2/
lastpage = log/display/last
firstpage = log/display/first
previouspage = log/display/previous
nextpage = log/display/next
One sample of using the property value. There will be a lot of case like these
//calling rest web service
DefaultHttpClient httpClient = new DefaultHttpClient(); //Apache HttpClient
HttpPost postRequest = new HttpPost(Ut_Properties.getUrl() + Ut_Properties.getLastpage());
Public class with static variables
package com.mastercard.mhe.utilities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component("ut_Properties")
#Scope("singleton")
public class Ut_Properties {
private static String url;
private static String lastpage;
private static String firstpage;
private static String previouspage;
private static String nextpage;
#Autowired
public Ut_Properties(#Value("${url}") String url,
#Value("${lastpage}") String lastpage,
#Value("${url}") String previouspage,
#Value("${lastpage}") String nextpage) {
Ut_Properties.setUrl(url);
Ut_Properties.setLastpage(lastpage);
Ut_Properties.setUrl(previouspage);
Ut_Properties.setLastpage(nextpage);
}
public static String getUrl() {
return url;
}
public static void setUrl(String url) {
Ut_Properties.url = url;
}
public static String getFirstpage() {
return firstpage;
}
public static void setFirstpage(String firstpage) {
Ut_Properties.firstpage = firstpage;
}
public static String getPreviouspage() {
return previouspage;
}
public static void setPreviouspage(String previouspage) {
Ut_Properties.previouspage = previouspage;
}
public static String getNextpage() {
return nextpage;
}
public static void setNextpage(String nextpage) {
Ut_Properties.nextpage = nextpage;
}
public static String getLastpage() {
return lastpage;
}
public static void setLastpage(String lastpage) {
Ut_Properties.lastpage = lastpage;
}
}
You could use something like this:
#Service
public class MyPropertiesServ implements InitializingBean {
#Autowired
protected ApplicationContext context;
private Properties properties;
private static MyPropertiesServ singleInst;
protected MyPropertiesServ () {
properties = new Properties();
singleInst= this;
}
#Override
public void afterPropertiesSet() throws Exception {
properties.load(context.getResource("classpath:file.properties").getInputStream());
}
public static String getStringProperty(String key) {
return singleInst.properties.getProperty(key);
}
}
Another example:
http://forum.spring.io/forum/spring-projects/container/35703-initialising-static-property-of-class-through-injection-on-startup
#Value is a lovely annotation but looking at your code I'm wondering if it is important for you that those variables representing the properties are static ?
If not you could avoid alot of clutter code by not making them static.
#Component
public class Ut_Properties {
#Value("${url}")
private String url;
// ...
public getUrl() { return url; }
#Component/Service/Controller
public class ClassFromWhereYouWantToAccessTheProperties {
#Inject
Ut_Properties utProperties;
// you could ofcourse just inject the properties in the classes where you need them instead of trying to gather them in one class.
#Value("${url}")
private String url;
public void someRandomMethod() {
utProperties.getUrl();
// vs
this.url;

Categories