Whats is the best Way to Define the Default Date Format - struts2

I am using Struts2,
I have a Action with Properties, I have a property Person, with "date" property.
class Person{
Date birthDate;
//more properties
}
class MyAction implements ModelDriven<Person>{
Person person;
public String create(){
person = new Person();
}
public String save(){
MyPersistenceContext.save(person);
}
#Override
public PhysicalPerson getModel() {
return person;
}
}
<label class="col-sm-2 control-label">Birthdate</label>
<div class="col-sm-4">
<s:textfield name="birthDate" cssClass="form-control"></s:textfield>
<s:fielderror name="birthDate"
fieldName="birthDate"></s:fielderror>
</div>
When I call the "create" method the Input shows as MM/dd/yy(short format), and when I do submit of the form the date is readed as the same format by the Struts, but I want to manage the date with the format "dd-MM-yyyy"
I see the page
http://www.mkyong.com/struts2/how-to-configure-global-resource-bundle-in-struts-2/
But, I think that the Listener method is called before of the Filter, and does not work Well.
what is the best way to manage a Locale Global Properties with Struts???
What is the best way to setting a Locale by Http Session User.
regards.

I have solved my problem with a Converter, i do not know if this is the best way... but finally I can do it.
public class CustomDateConverter extends StrutsTypeConverter {
private static Logger logger = LoggerFactory.getLogger(CustomDateConverter.class);
private static final String DEFAULT_FORMAT = "dd-MM-yyyy";
private static Map<String, DateFormat> instances = new LinkedHashMap<>();
static DateFormat getInstance(String format) {
if (instances.containsKey(format)) {
return instances.get(format);
}
DateFormat dateFormat = new SimpleDateFormat(format);
instances.put(format, dateFormat);
return dateFormat;
}
#Override
public Object convertFromString(Map map, String[] values, Class aClass) {
try {
logger.info("convert from string");
DateFormat dateFormat = getInstance(DEFAULT_FORMAT);
Date date = (Date) dateFormat.parse(values[0]);
return date;
} catch (ParseException e) {
return values[0];
}
}
#Override
public String convertToString(Map map, Object o) {
logger.info("convertToString");
DateFormat dateFormat = getInstance(DEFAULT_FORMAT);
return dateFormat.format(o);
}
}
for register the converter
I have created a file (resource)
src/main/resources/xwork-conversion.properties (Maven Structure)
with the next content:
# syntax: <type> = <converterClassName>
java.util.Date=com.roshka.javorai.webapp.struts.converter.CustomDateConverter

Related

How to modify binded value in MVVM Cross

I have a model from my json in a Xamarin MVVM app(ios). I want to add the "%" after the value? in the list "coinmarketcaplist" contains the value 24h_change, this is the value I want to add a % to, it's a string. I know that I should use a getter for it, but I don't know how since I'm fairly new to this. below is my ViewModel code:
public class CMCTableViewModel : MvxViewModel
{
protected readonly ICoinMarketCapService _coinMarketCapService;
public CMCTableViewModel(ICoinMarketCapService coinMarketCapService)
{
_coinMarketCapService = coinMarketCapService;
LoadData();
}
private List<CoinMarketCapModel> _coinMarketCapModelList;
public List<CoinMarketCapModel> CoinMarketCapModelList
{
get
{
return _coinMarketCapModelList;
}
set
{
_coinMarketCapModelList = value;
RaisePropertyChanged(() => CoinMarketCapModelList);
}
}
public async void LoadData()
{
CoinMarketCapModelList = await _coinMarketCapService.GetCoins();
}
}
TableCell:
internal static readonly NSString Identifier = new NSString("CMCTableCell");
public override void LayoutSubviews()
{
base.LayoutSubviews();
MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel> set = new MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel>(this);
set.Bind(lblName).To(res => res.Name);
set.Bind(lblPrice).To(res => res.percent_change_24h);
set.Bind(imgCoin)
.For(img => img.Image)
.To(res => res.image)
.WithConversion<StringToImageConverter>();
set.Apply();
}
}
edit: added cellview
Use a converter in your binding:
1) Define converter:
public class StringFormatValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format(parameter.ToString(), value);
}
}
2) Use it in your binding:
set.Bind(lblPrice).To(res => res.percent_change_24h).WithConversion<StringFormatValueConverter>("{0} %");
You can use this converter when you want to modify the input string by adding something around it, for example unit or currency

SmartGWT DateChooser disable specific dates

I need to disable (or make them for example red) specific dates in SmartGWT DateChooser. I was trying to use setDisabledDates(Date... disabledDates) and change cssStyle using setDisabledWeeenddayStyle, but it takes no effect. Any ideas how can I do that?
public class CustomDateItem extends DateItem {
private DateChooser chooser = new DateChooser();
public CustomDateItem() {
this("", "");
}
public CustomDateItem(String name, String title) {
super(name, title);
onInit();
}
private void onInit() {
Date date = new Date(2014, 06, 27);
chooser.setDisabledDates(date);
setPickerProperties(chooser);
}
}
This is my DateItem.java. However, if i try something like this:
public class CustomDateItem extends DateItem {
public CustomDateItem() {
this("", "");
}
public CustomDateItem(String name, String title) {
super(name, title);
onInit();
}
private void onInit() {
Date date = new Date(2014, 06, 27);
System.out.println(date);
getPickerProperties().setDisabledDates(date);
}
}
i got js error:
com.google.gwt.core.client.JavaScriptException: (TypeError) #com.smartgwt.client.util.JSOHelper::setAttribute(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)([null, string: 'disabledDates', JavaScript object(341)]): elem is null
but as you can see, "date" is not null and getPickerProperties() creates its own DateChooser.
Ok, resolved. Dates has to be declarated just like this:
Calendar cal1 = new GregorianCalendar(2014, 05, 26);
and all code should look like this:
public class DateItem extends com.smartgwt.client.widgets.form.fields.DateItem {
private DateChooser chooser = new DateChooser();
public DateItem(String name, String title) {
super(name, title);
onInit();
}
private void onInit() {
Calendar cal1 = new GregorianCalendar(2014, 05, 26);
Date[] dates = new Date[]{cal1.getTime()};
chooser.setDisabledDates(dates);
chooser.setDisabledWeekdayStyle("holidays");
chooser.setDisabledWeekendStyle("holidays");
setPickerProperties(chooser);
}
}
Hope it will help someone.

Allow empty string for EmailAddressAttribute

I have property in my PersonDTO class:
[EmailAddress]
public string Email { get; set; }
It works fine, except I want to allow empty strings as values for my model, if I send JSON from client side:
{ Email: "" }
I got 400 bad request response and
{"$id":"1","Message":"The Email field is not a valid e-mail address."}
However, it allows omitting email value:
{ FirstName: "First", LastName: 'Last' }
I also tried:
[DataType(DataType.EmailAddress, ErrorMessage = "Email address is not valid")]
but it does not work.
As far as I understood, Data Annotations Extensions pack does not allow empty string either.
Thus, I wonder if there is a way to customize the standard EmailAddressAttribute to allow empty strings so I do not have to write custom validation attribute.
You have two options:
Convert string.Empty to null on the Email field. Many times that is perfectly acceptable. You can make this work globally, or by simply making your setter convert string.Empty to null on the email field.
Write a custom EmailAddress attribute, since EmailAddressAttribute is sealed you can wrap it and write your own forwarding IsValid method.
Sample:
bool IsValid(object value)
{
if (value == string.Empty)
{
return true;
}
else
{
return _wrappedAttribute.IsValid(value);
}
}
Expansion on option 1 (from Web Api not converting json empty strings values to null)
Add this converter:
public class EmptyToNullConverter : JsonConverter
{
private JsonSerializer _stringSerializer = new JsonSerializer();
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
string value = _stringSerializer.Deserialize<string>(reader);
if (string.IsNullOrEmpty(value))
{
value = null;
}
return value;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
_stringSerializer.Serialize(writer, value);
}
}
and use on the property:
[JsonConverter(typeof(EmptyToNullConverter))]
public string EmailAddress {get; set; }
or globally in WebApiConfig.cs:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(
new EmptyToNullConverter());
It's Easy. Do This. Bye
private string _Email;
[EmailAddress(ErrorMessage = "Ingrese un formato de email vĂ¡lido")]
public string Email { get { return _Email; } set { _Email = string.IsNullOrWhiteSpace(value) ? null : value; } }
I used the suggestion from Yishai Galatzer to make a new ValidationAttribute called EmailAddressThatAllowsBlanks:
namespace System.ComponentModel.DataAnnotations
{
public class EmailAddressThatAllowsBlanks : ValidationAttribute
{
public const string DefaultErrorMessage = "{0} must be a valid email address";
private EmailAddressAttribute _validator = new EmailAddressAttribute();
public EmailAddressThatAllowsBlanks() : base(DefaultErrorMessage)
{
}
public override bool IsValid(object value)
{
if (string.IsNullOrEmpty(value.ToString()))
return true;
return _validator.IsValid(value.ToString());
}
}
}
Set TargetNullValue property of the binding to an empty string.
TargetNullValue=''

selectOneMenu with complex objects, is a converter necessary? [duplicate]

This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 7 years ago.
Is a Converter necessary for a <h:selectOneMenu> or <p:selectOneMenu> with arbitrary user-created classes as its values? I mean, is the following code supposed to work without a converter?
<p:selectOneMenu value="#{bean.language}">
<f:selectItems value="#{bean.allLanguages}" />
</p:selectOneMenu>
and
#Named(value = "bean")
#ConversationScoped
public class Bean {
private Language language; // appropriate getter and setter are present
public List<SelectItem> getAllLanguages() {
// populates a list of select items with Strings as item labels and Languages as item values
}
}
I have a similar code with an enum as the type (Language) and it works perfectly. But when I replace the type with a normal java class, I get a conversion error.
You need a converter here, as JSF will assume strings by default, that is the way you coded it. JSF has no idea how to convert your pseudo entities to strings and vice versa.
Some notes:
1 . Your getAsString method defines your identifier for your entities/POJOs, not what the JSF (or whatever) select gets as itemLabel.
2 . Your converter can dig into the DB for real entities using this infamous article:
http://balusc.blogspot.de/2011/09/communication-in-jsf-20.html#ConvertingAndValidatingGETRequestParameters
You can also use CDI annotations with that "pattern".
3 . Your value = "bean"is redundant and the CDI scope of choice is usually #ViewScoped. However, you have to keep in mind that CDI #Named + JSF #ViewScoped isn't working together without using Seam 3 or Apache MyFaces CODI.
You do not need a converter, if you use this little class that I wrote :-) It can back selectOne and selecteMany components. It requires that your class's toString() provides a one-to-one unique representation of your object. If you like, you could substitute a method name other than toString(), like toIDString()
To use ListBacker in your ManagedBean, use ListBacker<Type> wherever you would have used List<Type>
#ManagedBean
#RequestScoped
public class BackingBean {
private ListBacker<User> users; // +getter +setter
#PostConstruct
public void init() {
// fill it up from your DAO
users = new ListBacker<User>(userDAO.find());
}
// Here's the payoff! When you want to use the selected object,
// it is just available to you, with no extra database hits:
User thisOneIsSelected = users.getSelectedItemAsObject();
// or for multi-select components:
List<User> theseAreSelected = users.getSelectedItemsAsObjects();
}
In your xhtml file:
<p:selectOneMenu value="#{backingBean.users.selectedItem}">
<f:selectItems value="#{backingBean.users.contents}" var="item" itemValue="#{item.value}" itemLabel="#{item.label}" />
</p:selectOneMenu>
The ListBacker class:
public class ListBacker<T extends AbstractEntityBase> {
// Contains the String representation of an Entity's ID (a.k.a.
// primary key) and the associated Entity object
Map<String, T> contents = new LinkedHashMap<String, T>(); // LinkedHashMap defaults to insertion-order iteration.
// These hold values (IDs), not labels (descriptions).
String selectedItem; // for SelectOne list
List<String> selectedItems; // for SelectMany list
public class ListItem {
private String value;
private String label;
public ListItem(String value, String label) {
this.value = value;
this.label = label;
}
public String getValue() {
return value;
}
public String getLabel() {
return label;
}
}
public ListBacker() {}
public ListBacker(List<T> lst) {
put(lst);
}
public void clear() {
contents.clear();
selectedItem = null;
if(selectedItems != null) {
selectedItems.clear();
}
}
public List<ListItem> getContents() {
return convert(contents);
}
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
public T getSelectedItemAsObject() {
return convert(selectedItem);
}
public List<T> getSelectedItemsAsObjects() {
return convert(selectedItems);
}
public void put(T newItem) {
contents.put(newItem.toString(), newItem);
}
public void put(List<T> newItems) {
for (T t : newItems) {
put(t);
}
}
// PROTECTED (UTILITY) METHODS
protected List<ListItem> convert(Map<String, T> maps) {
List<ListItem> lst = new ArrayList<ListItem>();
for (Entry<String, T> e : maps.entrySet()) {
lst.add(new ListItem(e.getKey(), e.getValue().desc()));
}
return lst;
}
protected List<T> convert(List<String> ids) {
List<T> lst = new ArrayList<T>();
for (String id : ids) {
lst.add(convert(id));
}
return lst;
}
protected T convert(String id) {
return contents.get(id);
}
}
I have two toString() implementations, one for JPA entities:
public abstract class AbstractEntityBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString().toString());
}
/**
* Return the entity's ID, whether it is a field or an embedded ID class..
* #return ID Object
*/
protected abstract Object getIdForToString();
}
and one for JPA EmbeddedId's:
public abstract class CompositeKeyBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString());
}
/**
* Supports the class's toString() method, which is required for ListBacker.
* Compile a string of all ID fields, with this format:
* fieldName=StringVALUE,field2=STRINGvAlUE2,...,fieldx=stringvalue <br />
* Recommended: start with Eclipse's "generate toString()" utility and move it to getIdForToString()
* #return a 1-to-1 String representation of the composite key
*/
public abstract String getIdForToString();
}
An example implementation of getIdForToString(), for an entity that has one Id field:
#Override
public Object getIdForToString() {
return userID;
}
An example implementation of getIdForToString(), for an EmbeddedId that has two fields:
#Override
public String getIdForToString() {
return "userID=" + userID + ",roleID=" + roleID;
}

Unable to set membernames from custom validation attribute in MVC2

I have created a custom validation attribute by subclassing ValidationAttribute. The attribute is applied to my viewmodel at the class level as it needs to validate more than one property.
I am overriding
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
and returning:
new ValidationResult("Always Fail", new List<string> { "DateOfBirth" });
in all cases where DateOfBirth is one of the properties on my view model.
When I run my application, I can see this getting hit. ModelState.IsValid is set to false correctly but when I inspect the ModelState contents, I see that the Property DateOfBirth does NOT contain any errors. Instead I have an empty string Key with a value of null and an exception containing the string I specified in my validation attribute.
This results in no error message being displayed in my UI when using ValidationMessageFor. If I use ValidationSummary, then I can see the error. This is because it is not associated with a property.
It looks as though it is ignoring the fact that I have specified the membername in the validation result.
Why is this and how do I fix it?
EXAMPLE CODE AS REQUESTED:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ExampleValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// note that I will be doing complex validation of multiple properties when complete so this is why it is a class level attribute
return new ValidationResult("Always Fail", new List<string> { "DateOfBirth" });
}
}
[ExampleValidation]
public class ExampleViewModel
{
public string DateOfBirth { get; set; }
}
hello everybody.
Still looking for solution?
I've solved the same problem today. You have to create custom validation attribute which will validate 2 dates (example below). Then you need Adapter (validator) which will validate model with your custom attribute. And the last thing is binding adapter with attribute. Maybe some example will explain it better than me :)
Here we go:
DateCompareAttribute.cs:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class DateCompareAttribute : ValidationAttribute
{
public enum Operations
{
Equals,
LesserThan,
GreaterThan,
LesserOrEquals,
GreaterOrEquals,
NotEquals
};
private string _From;
private string _To;
private PropertyInfo _FromPropertyInfo;
private PropertyInfo _ToPropertyInfo;
private Operations _Operation;
public string MemberName
{
get
{
return _From;
}
}
public DateCompareAttribute(string from, string to, Operations operation)
{
_From = from;
_To = to;
_Operation = operation;
//gets the error message for the operation from resource file
ErrorMessageResourceName = "DateCompare" + operation.ToString();
ErrorMessageResourceType = typeof(ValidationStrings);
}
public override bool IsValid(object value)
{
Type type = value.GetType();
_FromPropertyInfo = type.GetProperty(_From);
_ToPropertyInfo = type.GetProperty(_To);
//gets the values of 2 dates from model (using reflection)
DateTime? from = (DateTime?)_FromPropertyInfo.GetValue(value, null);
DateTime? to = (DateTime?)_ToPropertyInfo.GetValue(value, null);
//compare dates
if ((from != null) && (to != null))
{
int result = from.Value.CompareTo(to.Value);
switch (_Operation)
{
case Operations.LesserThan:
return result == -1;
case Operations.LesserOrEquals:
return result <= 0;
case Operations.Equals:
return result == 0;
case Operations.NotEquals:
return result != 0;
case Operations.GreaterOrEquals:
return result >= 0;
case Operations.GreaterThan:
return result == 1;
}
}
return true;
}
public override string FormatErrorMessage(string name)
{
DisplayNameAttribute aFrom = (DisplayNameAttribute)_FromPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
DisplayNameAttribute aTo = (DisplayNameAttribute)_ToPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
return string.Format(ErrorMessageString,
!string.IsNullOrWhiteSpace(aFrom.DisplayName) ? aFrom.DisplayName : _From,
!string.IsNullOrWhiteSpace(aTo.DisplayName) ? aTo.DisplayName : _To);
}
}
DateCompareAttributeAdapter.cs:
public class DateCompareAttributeAdapter : DataAnnotationsModelValidator<DateCompareAttribute>
{
public DateCompareAttributeAdapter(ModelMetadata metadata, ControllerContext context, DateCompareAttribute attribute)
: base(metadata, context, attribute) {
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (!Attribute.IsValid(Metadata.Model))
{
yield return new ModelValidationResult
{
Message = ErrorMessage,
MemberName = Attribute.MemberName
};
}
}
}
Global.asax:
protected void Application_Start()
{
// ...
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DateCompareAttribute), typeof(DateCompareAttributeAdapter));
}
CustomViewModel.cs:
[DateCompare("StartDateTime", "EndDateTime", DateCompareAttribute.Operations.LesserOrEquals)]
public class CustomViewModel
{
// Properties...
public DateTime? StartDateTime
{
get;
set;
}
public DateTime? EndDateTime
{
get;
set;
}
}
I am not aware of an easy way fix this behavior. That's one of the reasons why I hate data annotations. Doing the same with FluentValidation would be a peace of cake:
public class ExampleViewModelValidator: AbstractValidator<ExampleViewModel>
{
public ExampleViewModelValidator()
{
RuleFor(x => x.EndDate)
.GreaterThan(x => x.StartDate)
.WithMessage("end date must be after start date");
}
}
FluentValidation has great support and integration with ASP.NET MVC.
When returning the validation result use the two parameter constructor.
Pass it an array with the context.MemberName as the only value.
Hope this helps
<AttributeUsage(AttributeTargets.Property Or AttributeTargets.Field, AllowMultiple:=False)>
Public Class NonNegativeAttribute
Inherits ValidationAttribute
Public Sub New()
End Sub
Protected Overrides Function IsValid(num As Object, context As ValidationContext) As ValidationResult
Dim t = num.GetType()
If (t.IsValueType AndAlso Not t.IsAssignableFrom(GetType(String))) Then
If ((num >= 0)) Then
Return ValidationResult.Success
End If
Return New ValidationResult(context.MemberName & " must be a positive number", New String() {context.MemberName})
End If
Throw New ValidationException(t.FullName + " is not a valid type. Must be a number")
End Function
End Class
You need to set the ErrorMessage property, so for example:
public class DOBValidAttribute : ValidationAttribute
{
private static string _errorMessage = "Date of birth is a required field.";
public DOBValidAttribute() : base(_errorMessage)
{
}
//etc......overriding IsValid....

Resources