JavaBeanBooleanPropertyBuilder for "Beans" without setters - java

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.

Related

Validating proxied Java Beans doesn't compare against correct values

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.

Spring expression parsing using evaluation context for boolean field

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().

#Required attribute checked for one bean but not another

I have a bean Config that has a required setter. However, when I don't set the setting in the bean config file I don't get an exception regarding the missing attribute.
public class Config extends MatchSet{
...
#Required
public void setSections(List<Section> section){...}
}
public class OtherClass{
...
#Required
public void setMatchSets(List<MatchSet> sets){...}
}
public interface MatchSet{...}
If I don't include the matchSets field of OtherClass I get a BeanInitializationException. But if I don't set the sections field of Config I don't get the exception. I am passing the instance of Config as one of the elements of the MatchSet list passed to OtherClass.
I have tried this using unit tests (SpringJUnit4ClassRunner) and using my main (ClassPathXmlApplicationContext) and the behavior is the same in either case.
Why is the #Required attribute not being checked for Config? Is it because it is being passed as a MatchSet?
Thanks
Turns out this was caused by a different issue. I did not have the getter/setter set up correctly. Primarily, this was because I had tried to set up method chaining and so was not returning null from the setter. Also, I was accepting a List in the setting but returning an ImmutableList from the getter. The combination was causing Spring to not recognize the setter and therefore not check

Filtered properties in java

I have a java program that uses a handful of .properties files. It chooses what properties file to use based on a parameter (mode) passed at runtime.
for example when the program is running in mode:a it uses a.properties file and when mode:b it'll uses b.properties file, etc.
I want to combine all these properties files into one common.properties and instead have different namespaces. For example in common.properties I'll have:
a.url = aaa
a.ip = aaa.aaa.aaa.aaa
b.url = bbb
b.ip = bbb.bbb.bbb.bbb
Right now, I instantiate the properties object in the main method and pass it to the other objects/methods that need to read something from the properties.But now that I've combined the properties I have to pass the mode: a or b as well so that they know what set of properties they should extract.
Is there a better way of creating a filtered instance of the properties file in the main method and then passing that to other object in a way that these objects are not aware of the mode: a or b, and just query the properties object for url and ip (not a.url or a.ip)
Don't pass the Properties object to other methods/objects. It's too low-level, especially now that you have to deal with this namespace thing. Encapsulate the Properties inside a dedicated object (let's call it "Configuration"), and pass this Configuration object.
public class Configuration {
private String mode;
private Properties properties;
public Configuration(String mode, Properties properties) {
this.mode = mode;
this.properties = properties;
}
public String get(String key) {
return properties.getString(mode + "." + key);
}
}
You could even extract the contract of this Configuration object into an interface, and make all objects depend on this interface rather than the concrete Configuration class, which would help in
changing the configuration strategy later if you want to (if you has done this from the start, you wouldn't have to change anything in all the objects now)
mocking the configuration in unit tests to make it return what you want.
You can extend the Properties class, add a getter and setter for the active namespace, and override the get() method to prepend the active namespace and call the super.get() method.

Is possible to set validation order with Hibernate Validator?

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.

Categories

Resources