I have a TextField which overrides it's getConverter method to add a Joda time converter instead:
new TextField<P>(id) {
#Override
public <P> IConverter<P> getConverter(Class<P> type) {
return (IConverter<P>) new JodaDateTimeConverter();
}
};
The converter returns null if input was invalid. However, I want to be able to flag this field as required, and I don't know how to do that:
textField.isRequired(true) does not work, because required checks are done before conversion. This doesn't work for non-empty but invalid inputs.
textField.add(.. some validator ..) does not work because no validator is called if the converter returned null.
I really don't see an approach to flag my date fields as required. Do you know how to do that? Probably my approach is not suited at all?
If you add an INullAcceptingValidator instead of a regular one, it will be called for null values too.
Subclassing your validators to return true on validateOnNullValue() might be helpfull too.
From the JavaDocs:
Indicates whether or not to validate the value if it is null. It is
usually desirable to skip validation if the value is null, unless we
want to make sure the value is in fact null (a rare use case).
Validators that extend this and wish to ensure the value is null
should override this method and return true.
Related
I know that MongoDb C# driver doesn't support projections so I searched a little bit and I found that many people uses a mongoCursor to perform such queries, I'm trying to select only specific fields and my code is the following:
public T GetSingle<T>(Expression<Func<T, bool>> criteria,params Expression<Func<T, object>>[] fields) where T : class
{
Collection = GetCollection<T>();
return Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields(Fields<T>.Include(fields)).SetLimit(1).SingleOrDefault();
}
I got and custom repository for users on top of that:
public User GetByEmail(string mail, params Expression<Func<User, object>>[] fields)
{
return GetSingle<User>(x=>x.Email==mail,fields);
}
this is the usage:
_repository.GetByEmail(email, x=>x.Id,x=>x.DisplayName,x=>x.ProfilePicture)
but I'm getting the fields included in the parameter but also all the Enums,dates and Boolean values that are part of the class User, the values that are string and not included in the field list are null so that's fine
what can I do to avoid that?
By using SetFields, you can specify what goes through the wire. However, you're still asking the driver to return hydrated objects of type T, User in this case.
Now, similar to say an int, enum and boolean are value types, so their value can't be null. So this is strictly a C#-problem: there is simply no value for these properties to indicate that they don't exist. Instead, they assume a default value (e.g. false for bool and 0 for numeric types). A string, on the other hand, is a reference type so it can be null.
Strategies
Make the properties nullable You can use nullable fields in your models, e.g.:
class User {
public bool? GetMailNotifications { get; set; }
}
That way, the value type can have one of its valid values or be null. This can, however, be clumsy to work with because you'll have to do null checks and use myUser.GetMailNotifications.Value or the myUser.GetMailNotifications.GetValueOrDefault helper whenever you want to access the property.
Simply include the fields instead this doesn't answer the question of how to it, but there are at least three good reasons why it's a good idea to include them:
When passing a User object around, it's desirable that the object is in a valid state. Otherwise, you might pass a partially hydrated object to a method which passes it further and at some point, someone attempts an operation that doesn't make sense because the object is incomplete
It's easier to use
The performance benefit is negligible, unless you're embedding huge arrays which I would suggest to refrain from anyway and which isn't the case here.
So the question is: why do you want to make all the effort of excluding certain fields?
I am writing an application which uses ORMLite to connect to a back-end database. Since the application will be run over VPN I am trying to minimize database calls.
In order to minimize database calls I have created a set of classes to wrap the values for each field. Each wrapper class stores the original value returned from the database and also a current value. This allows things like reverting to the original value, or checking whether the value is dirty (ie. only update the database if one or more fields are dirty).
The implication of this regarding ORMLite is that ORMLite never returns a null value when it queries the database (even if the database returns null). If there is a null value in the database it returns a fully initialized "wrapper" with the currentValue and originalValue variables set to null.
It seems that the right place to do this is in a custom persister such as (where StatefulIntegerProperty is the wrapper for the Integer):
public class StatefulIntegerPersister extends BaseDataType {
... misc. other code
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
Integer result = results.getInt(columnPos);
return new StatefulIntegerProperty((results.wasNull(columnPos)) ? null : result);
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) throws SQLException {
return sqlArg;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object obj) throws SQLException {
return ((StatefulIntegerProperty)obj).getCurrentValue();
}
#Override
public boolean isStreamType() {
return true; // this is a hack to work around ORMLite setting the value to null in the FieldType.resultToJava function
}
}
I have three questions:
Is this the correct approach?
In the ORMLite FieldType.resultToJava function it seems to do a null check and will replace my wrapper with null if the database returned null. Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach, and will I find later an unintended negative side effect?
What is the difference between the resultToSqlArg and sqlArgToJava methods in a custom persister, and specifically, which one of these should I use to wrap the value returned from the DB, and then what should I be doing in the other?
Is this the correct approach?
I don't understand why anything that you are doing here minimizes database calls. Can you start a discussion on the users' mailing list?
Right now you are overriding the resultToSqlArg(...) method when I think you want the sqlArgToJava(...). See below.
Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach...
Hrm. If it works then fine but it seems dangerous to use this setting in this manner. If I changed the behavior of the isStreamType() method then this may break your code. At the very least you should have unit tests to confirm this behavior that will break if you upgrade ORMLite.
That said, there is good handling in the code specifically around null values if isStreamType() is true.
What is the difference between the resultToSqlArg and sqlArgToJava...
I've fleshed out the javadocs for these.
resultToSqlArg takes the object from the SQL results and turns it into a java-object suitable to be an argument to SQL commands. For example, if you have a date-long type, this will extract a Long value from the database results.
sqlArgToJava takes the sql-arg value and converts it into our Java field. For example, if you have a date-long type, this will take a Long value and convert it into a Date which matches the entity field.
I think you should override the sqlArgToJava and not the resultToSqlArg.
I would like to use FindBugs to create a report about an application.
I run it and it doesn't find a potential bug like this:
public List<String> getListTrace(A object) {
String arg = object.getArg();
...
}
If object is null, my application will be down.
Why FindBugs doesn't raise an alert?
Findbugs doesn't know if object is allowed to be null or not. You can tell it by using annotations:
import javax.annotation.Nullable;
...
public List<String> getListTrace(#Nullable A object) {
This tells Findbugs (and people reading the code) that it is okay to pass null as the argument to getListTrace. So Findbugs will warn you if you dereference object without checking for null.
That code doesn't look like it has a bug.
If you changed the code to check if object was null, what would you do? The most reasonable action would probably to throw a NullPointerException, right?
That's exactly what your code snippet does; it just lets java do the test automatically when accessing a method.
That this function doesn't check for a null pointer is not a bug. The bug would be if someone passed a null pointer into your function and wasn't prepared for it raising a NullPointerException.
Findbug cannot detect potential null pointer accesses. But Eclipse can give you a warning for potential null pointer access, if you activate the corresponding compiler warning in the preferences.
Raising bug report in such case would result in really big noise. You would get thousands of irrelevant bug messages in the perfectly correct code. Actually FindBugs does smarter thing. If it discovers that the method dereferences the argument without a null-check, it marks internally this method argument as #Nonnull. If you have an explicit annotation (like in TimK answer) which contradicts with this, you will get a warning. Otherwise FindBugs assumes that nobody uses this method with possibly-null argument. And when somebody actually does this, you will get a corresponding warning on the call site. Here's an example:
import java.util.Collections;
import java.util.List;
public class FBNull {
static class A {
String getArg() {
return "str";
}
}
public static List<String> getListTrace(A object) {
String arg = object.getArg();
return Collections.singletonList(arg);
}
public void callSite(A a) {
if (a == null) {
System.out.println("a is null");
}
System.out.println(getListTrace(a)); // NP_NULL_PARAM_DEREF
}
}
From the FindBugs poit of view getListTrace() method is ok. However the callSite method has a bug. It checks its argument for null explicitly, thus it can be null due to application logic. However, it's later passed to getListTrace() which immediately dereferences the argument. Thus you have a bug warning inside the getListTrace() method saying:
Bug: Null passed for non-null parameter of getListTrace(FBNull$A) in FBNull.callSite(FBNull$A)
This method call passes a null value for a non-null method parameter. Either the parameter is annotated as a parameter that should always be non-null, or analysis has shown that it will always be dereferenced.
So if you actually can pass nulls, it can be detected on the call sites.
I am making a custom ActiveForm method, but it requires the model to have a certain custom validator attached the the attribute that is being passed through (otherwise who knows what will happen!?)
My question is simply... is there a way to run this check in the code that is reliable?
I don't want to add the validator at runtime. That would create confusion and possibly let someone use this type of field where it ought not be used.
So I want to say something like:
if( model NOT HAVE validationMethod ON property)
throw Exception;
I'm also not sure why you want to do this, but in addition to viewing the rules array you can do:
$model->getValidators($attribute)
to check which validators are active for a particular attribute (or all attributes, if the arg is null. (I'm assuming $attribute = property in your example.)
This will return all the validator objects that are active for the current scenario and you can check if a predefined or custom class exists. It also gets you a bit more info than just the rules array (i.e., the properties of the validator class).
I'm trying to integrate NHibernate.Validator with ASP.NET MVC client side validations, and the only problem I found is that I simply can't convert the non-interpolated message to a human-readable one. I thought this would be an easy task, but turned out to be the hardest part of the client-side validation. The main problem is that because it's not server-side, I actually only need the validation attributes that are being used, and I don't actually have an instance or anything else at hand.
Here are some excerpts from what I've been already trying:
// Get the the default Message Interpolator from the Engine
IMessageInterpolator interp = _engine.Interpolator;
if (interp == null)
{
// It is null?? Oh, try to create a new one
interp = new NHibernate.Validator.Interpolator.DefaultMessageInterpolator();
}
// We need an instance of the object that needs to be validated, se we have to create one
object instance = Activator.CreateInstance(Metadata.ContainerType);
// we enumerate all attributes of the property. For example we have found a PatternAttribute
var a = attr as PatternAttribute;
// it seems that the default message interpolator doesn't work, unless initialized
if (interp is NHibernate.Validator.Interpolator.DefaultMessageInterpolator)
{
(interp as NHibernate.Validator.Interpolator.DefaultMessageInterpolator).Initialize(a);
}
// but even after it is initialized the following will throw a NullReferenceException, although all of the parameters are specified, and they are not null (except for the properties of the instance, which are all null, but this can't be changed)
var message = interp.Interpolate(new InterpolationInfo(Metadata.ContainerType, instance, PropertyName, a, interp, a.Message));
I know that the above is a fairly complex code for a seemingly simple question, but I'm still stuck without solution. Is there any way to get the interpolated string out of NHValidator?
Ok, so I know this is an old question, but I stumbled across this when trying to do the same thing, and it helped me get started - so I thought I would provide an answer.
I think the code in the question was on the right track but there are a couple of problems. The interpolator was not completely initialised with the ResourceManager and Culture details, and it doesn't seem to allow for the fact that you can only have one DefaultMessageInterpolator per validation attribute. Also, you don't need an instance of the object you are validating to get an interpolated message.
In the code in the question, where you are initialising the interpolator with the attribute value, you also need to initialise the interpolator with details of the ResourceManager to be used.
This can be done using the overloaded Initialize method on DefaultMessageInterpolator which has the following signature:
public void Initialize(ResourceManager messageBundle,
ResourceManager defaultMessageBundle,
CultureInfo culture)
The first parameter is a user-defined ResourceManager in case you want to use your own resource file for error messages, you can pass a null if you just want to use the default ResouceManager, the second parameter is the default ResourceManager - you can pass
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.GetExecutingAssembly());
for this, the last parameter is the culture to use, (NHibernate.Validator comes with resource files with validation messages in several languages) - if you pass a null in to this it will just use CultureInfo.CurrentCulture
Lastly, you can only have one DefaultMessageInterpolator per attribute, so you will need to create a new DefaultMessageInterpolator for each validation attribute. You could make use of the DefaultMessageInterpolatorAggregator to handle this, or just roll your own.
I hope this helps someone.
Thanks for your help all--I'd upvote if I could. I just wanted to add that in addition to the first Initialize call on the DefaultMessageInterpolator that Stank illustrates, I also had to make a second different Initialize call to fully initialize it (I was getting some Null Reference Exceptions using only the first call). My code is as follows:
string interpolatedMessage = "";
DefaultMessageInterpolator interpolator = new DefaultMessageInterpolator();
interpolator.Initialize(null,
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.Load("NHibernate.Validator")),
CultureInfo.CurrentCulture);
interpolator.Initialize(attribute as Attribute);
if (attribute is IValidator && attribute is IRuleArgs)
{
IValidator validator = attribute as IValidator;
IRuleArgs ruleArgs = attribute as IRuleArgs;
InterpolationInfo interpolationInfo = new InterpolationInfo(
validatableType,
null,
propertyName,
validator,
interpolator,
ruleArgs.Message);
interpolatedMessage = interpolator.Interpolate(interpolationInfo);
}