I am using spring-expression for parsing values in a class(present in jar). After i read this value i set it in the target class [a typical use case of spring-expression]. However, all the field's value from the class in jar can be parsed except, boolean value. In the source class, it is declared like this:
boolean isVerified;
//getter
public isVerified() {
return isVerfied;
}
Spring-expression code to read this value:
Expression sourceExp = parser.parseExpression(<source field string>);
sourceExp.getValue(sourceContext);
and this fails. The message is
Couldn't find property isVerified
My question is it because spring is looking for isIsVerified method rather than isVerified method? If not this what could be the reason for failure?
You don't show your expression but SpEL uses JavaBean semantics when accessing bean properties. It knows nothing about the internals of the referenced bean. When it encounters a property request...
"x.foo"
it tries to find the getter getFoo() (any return type) and if that's not found, it looks for isFoo() if it returns boolean.
I suspect you are trying to use x.isVerified. There is no such getter; you need to use x.verified, or you can invoke the method itself x.isVerified().
Related
I'm trying to make a CDI extension which will validate a Java object which is bound to configuration values.
public class ExampleConfig {
#Range(min = 1000, max = 9999)
private int value;
#Inject
public ExampleConfig(#ConfigProperty(name = "value") int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
When I make the above class with the #Singleton annotation, it works correctly. On startup the CDI extension validates the class which reads an environment variable called "value".
Class: com.example.ExampleConfig
Property: value
Value: 22222
Reason: must be between 1000 and 9999
When I replace #Singleton with #ApplicationScoped instead, when injecting and using this class myself, it works as intended, but in the CDI extension, javax.validation.Validator appears to always treat the value as 0.
Class: com.example.ExampleConfig$Proxy$_$$_WeldClientProxy
Property: value
Value: 0
Reason: must be between 1000 and 9999
I'm struggling to see why this is the case, is anyone able to provide guidance on how to read the value correctly?
Two things I've been trying to achieve to no avail is:
Have the extension enforce initialization on startup for respective classes.
Make the CDI extension wait until the bean has initialized.
The following is how I'm calling #validate:
public void afterDeploymentValidation(#Observes AfterDeploymentValidation adv, BeanManager bm) {
Set<ConstraintViolation<?>> allViolations = new HashSet<>();
for (Class<?> type : types)
{
final Object typeImpl = BeanProvider.getContextualReference(bm, type, false);
Set<ConstraintViolation<?>> violations = (Set<ConstraintViolation<?>>)(Object)validator.validate(typeImpl);
allViolations.addAll(violations);
}
// Omitted for brevity.
}
Several things:
First of all, if all you're trying to do is get Bean Validation working, just put the Hibernate Validator CDI project on your runtime classpath. Nothing else needed; the end.
If you're doing something else, you're probably running into the fact that a contextual reference to a bean in a normal scope is a client proxy. In less stuffy terms, that means it's a proxy, a shell, a holder—and its "innards" (its referent, the thing it is proxying) is not "inflated" until some method is called on the proxy, like toString() or a business method. I'm guessing that what's happening in your case is the validator is looking for validatable fields directly on the proxy.
One way to "inflate" a contextual reference is to just call toString() on it right away before doing something else. So just call typeImpl.toString() before you do anything else to "inflate" the reference.
I don't think there's any guarantee that the proxy will somehow magically make the proxied object's fields available to you. For that, you'll need to get the inner proxied object. Each CDI implementation does this a little differently, but in Weld you can get this programmatically with some casting.
I found this post for connecting a Java Bean as property binding with an existing JavaFX property. The binding should target a boolean property:
class MyClass {
private boolean loaded;
public boolean isLoaded() {
return loaded;
}
// Value changed internally
}
For real beans, meaning beans with setters the following works like a charm. But I've the problem that there's no setter for the loaded property, just because it's set internally and shouldn't be modifyable for external classes.
BooleanProperty loadedProeprty = new JavaBeanBooleanPropertyBuilder()
.bean(bean)
.name("loaded")
.getter("isLoaded")
.build();
Is there any way to create still a property for such "beans" without a setter? For now I just get a NoSuchMethodException for the expected setter MyClass.setLoaded(boolean).
Use ReadOnlyJavaBeanBooleanPropertyBuilder instead.
Normal properties in JavaFX are always read/write and thus require a setter. The read only variant creates a read only property and thus does not require a setter.
I want to use non spring bean class object as parameter for jersey web service class method. But it is giving missing dependency error at build time.
My code is:
#Component
#Path("/abcd")
public class ActorServiceEndpoint {
#POST
#Path("/test/{nonspringBean}")
#Produces(MediaType.APPLICATION_XML)
public void addActor(#PathParam("nonspringBean") MyNonSpringBeanClass nonspringBean){
}
}
The thing is path parameters come in String form. As per the specification, if we want the have a custom type be injected as a #PathParam, the custom class, should have one of three things:
A public static valueOf(String param) that returns the type
A public static fromString(String param) that returns the type
Or a public constructor that accepts a String
Another option implement a ParamConverter. You can see an example here.
If you don't own the class (it's a third-party class that you can't change) then your only option is to use the ParamConverter/ParamConverterProvider pair.
In either of these cases you'll want to construct the instance accordingly by parsing the String either in the constructor or in one of the above mentioned methods. After doing this, the custom type can be made a method parameter with the annotation.
The same holds true for other params, such as #FormParam, #HeaderParam, #QueryParam, etc.
It would help if you gave a bit more details of the error you're getting, but I see two problems with your code snippet:
The correct Spring annotation is #PathVariable, #PathParam is probably from another package. This doesn't apply as I guess you're using JAX-RS, not Spring annotations.
I'm not sure what converters are applied to path variables, but in any case it would need to have one for MyNonSpringBeanClass. I would take a String parameter and then instantiate MyNonSpringBeanClass myself in the function body.
I am wondering why eclipse produces the following getter and setter if i used the following boolean:
boolean isLifeTimeMember
The getter should be isIsLifeTimeMember() and not isLifeTimeMember()
I think it affected calling the variable isLifeTimeMember in JSP. because it will look at JSP and map it to isIsLifeTimeMember() getter method.
Error will result because there is no isIsLifeTimeMember() method but the getter generated by eclipse is isLifeTimeMember()
Thank you.
Eclipse name generation rules are that boolean getters should start with is. If the variable name already starts with is, then it thinks that no additional prefix is necessary.
Eclipse has a setting that controls the use of is for generated boolean getters. Open up Preferences and navigate to Java > Code Style. There you can uncheck the option "Use 'is' prefix for getters that return boolean". Eclipse-generated boolean getters will then start with "get", just like all the others.
Java has no problem, by the way, in having a field and a method with the same name.
However, having property names that start with "is" will probably cause problems with jsp. As described in this thread, it's better to avoid property names that read like questions (isLifeTimeMember) and instead just use the property itself as the property name (lifeTimeMember).
Code Example:
boolean lifeTimeMember;
public boolean isLifeTimeMember() {
return lifeTimeMember;
}
public void setLifeTimeMember(boolean lifeTimeMember) {
this.lifeTimeMember = lifeTimeMember;
}
And in JSP if you need to use this variable simply use variable name "lifeTimeMember".
In case of boolean variable, eclipse prepends is to the variable name to form the getter name. I.e. If variable is boolean present; then the gemerated getter would be named isPresent();
Its not advisable to have an is in the variable name.
If the variable name is ispresent , on jsp you will lookup by variable name ispresent which in turn looks up for its getter, its an boolean so it assumes getter would be isispresemt(); which was not there as the getter setter generator in eclipse does not add an is in case that already existe in variable name.
thus an exception could not find the field ispresent is expected to be thrown
having an is in field name , can cause problems, avoid using them
I use #AssertTrue annotation to ensure the execution of a method that sets some default values (always returns true). These set values are validated as #NotEmpty (these are Strings). So I need to guarantee that method annotated with #AssertTrue is executed strictly before that fields annotated with #NotEmpty.
Simplified code example (not included Hibernate annotations):
public class MyClass {
#NotEmpty
private String myField = null;
#SuppressWarnings("unused")
#AssertTrue
private boolean fillDefaultValues() {
if (this.myField == null) {
this.myField = "default value";
}
return true;
}
}
This seems to me like a hack. For two reasons:
you always return true and assert it for the sole purpose of executing an initialization code
you expect the framework to access and validate your bean in a specific order in order to execute an initialization code
The thing in common is "initialization code". In order to achieve what you want, you can register a listener and execute the initialization method before the validation happens. Here's the documentation of hibernate-validator - it tells you about event listeners.
You can also manually set the default values in your service layer (since you seem to be using anemic data model). Since this seems like a business logic, it'd better be in the service method, before the object is persisted.
Finally I have solved my problem.
Debuging validator stack trace, I have seen that first it process beanValidators, and then, memberValidators. So the only I have to do is define my initialization code in a class constraint.
I have defined a new class annotation where, depending on the type of the pojo received, I set default values.
I have verified that this code is executed before than any other (member) constarint, like #NotEmpty, etc.