So I created a class with two simple public strings
public final class Right {
private Right() {
super();
}
public static final String AUTH = "hasAuthority('admin') or hasAuthority('mod')";
}
When I used it together with the #PreAuthorize annotation at my controllers it works like a charm. I do not like that it is hardcoded. For this reason I've put the roles in the properties and I tried to use it as a component:
#Component("authRule")
public class AuthRule {
#Value("${role.administrator}")
private String roleAdmin;
#Value("${role.moderator}")
private String roleMod;
public String getRightAccess() {
return "hasAuthority('" + roleAdmin+ "')" + " or hasAuthority('" + roleMod+ "')";
}
}
When i use it in my PreAuthorize as :
#PreAuthorize("#authRule.getRightAccess()")
I am getting back an exception of Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value 'hasAuthority('admin') or hasAuthority('mod')
if I hardcoded in the PreAuthorize. I am quite confused with this. Anyone any ideas?
Thanks in advance for all the responses.
I've had a quick read of the documentation; https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-pre-post-annotations
It's likely that the value provided to the annotation is parsed only once. I think you need it to parse twice; once to trigger your custom component's method getRightAccess(). And a second time to parse the String result returned by that method. There are examples here if you do a general search for "Boolean"; https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html
// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
societyContext, Boolean.class);
So you probably need something like this in your getRightAccess() method;
return parser.parseExpression("hasAuthority('"+roleAdmin+"') or hasAuthority('"+roleMod+"')").getValue(Boolean.class);
I'm trying to change the type of a parameter on the generated swagger contract, but it looks like the #ApiParam#type property is not working.
ResponseEntity<Void> delete(
#ApiParam(
value = "The id of the object",
required = true,
type = "java.lang.String") Integer id);
Doing this has no effect in swagger-ui, and id is still being shown as Integer.
Does anyone knows a workaround for this?
You have to use #ApiImplicitParam
#ApiImplicitParam(dataType = "string", name = "id")
ResponseEntity<Void> delete(Integer id);
I think you should use "string" not "java.lang.String".
The annotation is not #ApiParam, you can use #ApiImplicitParam, and use dataType="string"
The supported type as below:
integer
long
float
double
string
byte
boolean
date
dateTime
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.
I have a method that returns a list and I want to cache it based on the parameters passed.The parameters are 4 and integers how can I configure this with SpEL?
I am using spring version 4.0.6.RELEASE.
You can use something like this
#Cacheable(value ="CacheService", key="#par1 + #par2 +#par3 +#par4" )
The default is to use all the parameters of the method, whose return value is cached.
For example.
#Cacheable(value ="CacheService")
public ReturnType methodName(int param1, int param2, int param3, int param4) {
//method body
}
You can use the class SimpleKey (org.springframework.cache.interceptor.SimpleKey):
#Cacheable(value="getPerson", key="new SimpleKey(#id, #age, #socialSecNo)")
public String getPerson(Integer id, Integer age, Integer socialSecNo){
...
}
I am trying to read a config file and I want to use that properties value in some algebraic operations. So I need to convert the string returned by prop.getProperty(String str) into an integer.
I have tried converting it using:
1.)
Integer value = null;
String string = getProperty(key);
if (string != null)
value = new Integer(string);
return value;
2.)
String noofdivs = prop.getProperty("NO_OF_INITIAL_DIVS");
Integer noOfInitialDivs = Integer.valueOf(noofdivs);
3.)
String xyz = prop.getProperty("NO_OF_LINES_IN_A_DIV");
Integer noOfLinesInDiv = Integer.getInteger(xyz);
but none of them is working.
Can anybody help me out with this?
int value = Integer.parseInt(string);
You can then check for a NumberFormatException to see if it was properly parsed.
Even if it could be a little bit overengineered here, you could use Apache Commons Configuration to avoid converting yourself the properties. The framework has also the advantage to throw a ConversionException if the property your are reading is not of the expected type.
Integer value = env.getProperty("name property", Integer.class);