I've created a custom validator to validate dateTimefield.
My problem is that I can't add it to the
datetimefield variable
The method add(IValidator<? super Date>) in the type FormComponent<Date> is not applicable for the arguments (DateTimeFieldValidator)
This is the error I'm getting.
Is there any standard way to validate DateTimeField?
package validators;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import org.apache.wicket.extensions.yui.calendar.DateTimeField;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidator;
import org.apache.wicket.validation.ValidationError;
public class DateTimeFieldValidator implements IValidator<DateTimeField> {
/**
*
*/
private static final long serialVersionUID = 2342344609244L;
public DateTimeFieldValidator() {
}
private void error(IValidatable<DateTimeField> validatable, String errorKey) {
ValidationError error = new ValidationError();
error.addMessageKey(getClass().getSimpleName() + "." + errorKey);
validatable.error(error);
}
public void validate(IValidatable<DateTimeField> validatable) {
DateTimeField dateTime = (DateTimeField) validatable.getValue();
if ( dateTime== null){
error(validatable, "invalid.datetime");
}
else{
if( dateTime.getHours()!=null){
if( dateTime.getHours()>12 || dateTime.getHours()<0){
error(validatable, "invalid.hour");
}
}
else{
error(validatable, "invalid.hour");
}
if(dateTime.getMinutes()!=null){
if( dateTime.getMinutes() > 60 ){
error(validatable, "invalid.hour");
}
}else {
error(validatable, "invalid.minutes");
}
if( dateTime.getDate() == null ){
error(validatable, "invalid.date");
}
}
}
boolean isLegalDate(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setLenient(false);
return sdf.parse(s, new ParsePosition(0)) != null;
}
}
This is how I'm adding the validator.
startDateTimeField.add(new DateTimeFieldValidator());
Your DateTimeFieldValidator must implement IValidator<Date> instead of IValidator<DateTimeField>
I end up validating the datetimefield following way ..
And find out the datetimefield( yui ) have built in validation - which actually take care of the all the basic validations.
All you have to do is put a XXX.properties file in the folder -
you can also add your own error key and message - like I used startDate.after.enddate
IFormValidator validator = new AbstractFormValidator() {
/**
*
*/
private static final long serialVersionUID = -3252346839511722L;
public FormComponent<?>[] getDependentFormComponents() {
return new FormComponent[] { startField, endField };
}
ValidationError error = new ValidationError();
public void validate(Form<?> form) {
Date startDate = (Date) startField.getConvertedInput();
if(endField.isEnabled()){
Date endDate = (Date) endField.getConvertedInput();
if (endDate.before(startDate)){
error.addMessageKey(getClass().getSimpleName() + "startDate.after.enddate");
startField.error(error);
}
}
}
};
logForm.add(validator );
Related
I'm trying to map different formats onto 3 xsd types, xs:dateTime, xs:date, and xs:time. I'm doing a bit of codegen in my project, and do not have a bindings file, though I do have a package-info.
#javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
#javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = com.codegen.pojo.lib.adapters.XmlDateTimeFormatter.class, type = com.codegen.pojo.lib.types.IXmlDateTime.class)
})
#javax.xml.bind.annotation.XmlSchemaTypes({
#javax.xml.bind.annotation.XmlSchemaType(name = "dateTime", type = com.codegen.pojo.lib.types.XmlDateTime.class),
#javax.xml.bind.annotation.XmlSchemaType(name = "date", type = com.codegen.pojo.lib.types.XmlDate.class),
#javax.xml.bind.annotation.XmlSchemaType(name = "time", type = com.codegen.pojo.lib.types.XmlTime.class)
})
#com.codegen.pojo.lib.annotations.XMLDateTimeFormat(format = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXX")
#com.codegen.pojo.lib.annotations.XMLDateFormat(format = "yyyy-MM-dd'T'")
#com.codegen.pojo.lib.annotations.XMLTimeFormat(format = "'T'HH:mm:ss.SSSXXXX")
package my_pkg;
All 3 of the Xml(Date/Time) classes mentioned in the XmlSchemaType annotations implement the IXmlDateTime interface.
The adapter:
public class XmlDateTimeFormatter extends XmlAdapter<String, IXmlDateTime> {
private final DateTimeFormatter dateTimeFormat;
private final DateTimeFormatter dateFormat;
private final DateTimeFormatter timeFormat;
public XmlDateTimeFormatter(String dateTimeFormatPattern, String dateFormatPattern, String timeFormatPattern) {
dateTimeFormat = dateTimeFormatPattern == null ? null : DateTimeFormatter.ofPattern(dateTimeFormatPattern);
dateFormat = dateFormatPattern == null ? null : DateTimeFormatter.ofPattern(dateFormatPattern);
timeFormat = timeFormatPattern == null ? null : DateTimeFormatter.ofPattern(timeFormatPattern);
}
#Override
public String marshal(IXmlDateTime dateTime) throws Exception {
if (dateTime instanceof XmlDateTime) {
return dateTimeFormat.format(dateTime.getCalendar().toGregorianCalendar().toZonedDateTime());
} else if (dateTime instanceof XmlDate) {
return dateFormat.format(dateTime.getCalendar().toGregorianCalendar().toZonedDateTime());
} else if (dateTime instanceof XmlTime) {
return timeFormat.format(dateTime.getCalendar().toGregorianCalendar().toZonedDateTime());
}
return null;
}
#Override
public IXmlDateTime unmarshal(String dateTime) throws Exception {
XMLGregorianCalendar calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTime);
QName xmlFormat = calendar.getXMLSchemaType();
if (xmlFormat.equals(DatatypeConstants.DATETIME)) {
return new XmlDateTime(calendar);
} else if (xmlFormat.equals(DatatypeConstants.DATE)) {
return new XmlDate(calendar);
} else if (xmlFormat.equals(DatatypeConstants.TIME)) {
return new XmlTime(calendar);
}
return null;
}
The adapter is added to a Marshaller/Unmarshaller created from a JAXBContext. Unfortunately, neither the marshal or unmarshal get called. Any thoughts on how I could fix this?
I have a class with three pairs of Date fields.
public static final class Filter {
private final Date startDateFrom;
private final Date startDateTo;
private final Date endDateFrom;
private final Date endDateTo;
private final Date regDateFrom;
private final Date regDateTo;
public Filter(Date startDateFrom, Date startDateTo,
Date endDateFrom, Date endDateTo,
Date regDateFrom, Date regDateTo) {
this.startDateFrom = startDateFrom;
this.startDateTo = startDateTo;
this.endDateFrom = endDateFrom;
this.endDateTo = endDateTo;
this.regDateFrom = regDateFrom;
this.regDateTo = regDateTo;
}
}
So I need to check that at least one pair has both not null Dates and check that DateFrom is before or equals DateTo for all not-null dates.
I've made this to check if there is at least one pair:
public boolean allDatesMissing() {
if (startDateFrom != null && startDateTo != null) {
return false;
} else if (endDateFrom != null && endDateTo != null) {
return false;
} else if (regDateFrom != null && regDateTo != null) {
return false;
}
return true;
}
And this to check fromDate is before toDate:
public void checkDates(Date from, Date to) throws RequestException{
if (from != null) {
if (to != null) {
if (from.after(to)) {
throw new MyException(INCORRECT_DATES_PERIOD);
}
} else {
throw new MyException(MISSING_PARAMETER);
}
} else if (to != null){
throw new MyException(MISSING_PARAMETER);
}
}
Is there any simplier way to do the same?
You have declared the Filter class static..Then it should be a inner class..
package demo;
import java.util.Date;
public class FilterDemo {
public static void main(String[] args) throws Exception {
Filter f = new Filter(new Date(2017, 01, 01), new Date(2017, 02, 01),
null, null, null, null);
}
public static final class Filter {
private final Date startDateFrom;
private final Date startDateTo;
private final Date endDateFrom;
private final Date endDateTo;
private final Date regDateFrom;
private final Date regDateTo;
// dateCounter will maintain the count of correct date pair
public static int dateCount = 0;
public Filter(Date startDateFrom, Date startDateTo, Date endDateFrom,
Date endDateTo, Date regDateFrom, Date regDateTo)
throws Exception {
this.startDateFrom = startDateFrom;
this.startDateTo = startDateTo;
isExist(startDateFrom, startDateTo);
this.endDateFrom = endDateFrom;
this.endDateTo = endDateTo;
isExist(endDateFrom, endDateTo);
this.regDateFrom = regDateFrom;
this.regDateTo = regDateTo;
isExist(regDateFrom, regDateTo);
// throw exception after initializing 3 pair,if count is still 0
if (dateCount == 0)
throw new Exception("All pairs are null");
}
public static void isExist(Date from, Date to) throws Exception {
if (from != null && to != null) {
checkDates(from, to);
}
}
public static void checkDates(Date from, Date to) throws Exception {
if (from.getTime() > to.getTime()) {
throw new Exception("INCORRECT_DATES_PERIOD");
}
//increase dateCount if date pair is correct
dateCount++;
}
}
}
This code:
#Override
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() {
String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS;
Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery);
List<FactCodeDto> factDtoList = query.list(); //line 133
return factDtoList;
}
calling this method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
gives me a ClassCastException -> part of the trace:
Caused by: java.lang.ClassCastException: org.bamboomy.cjr.dto.FactCodeDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125)
at org.bamboomy.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133)
Which is pretty strange because, indeed, if you look up the source code of Hibernate it tries to do this:
#Override
#SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value ); //line 102
}
Which doesn't make any sense...
target is of type Class and this code tries to cast it to Map,
why does it try to do that???
any pointers are more than welcome...
I'm using Hibernate 5 (and am upgrading from 3)...
edit: I also use Spring (4.2.1.RELEASE; also upgrading) which calls these methods upon deploy, any debugging pointers are most welcome as well...
edit 2: (the whole FactCodeDto class, as requested)
package org.bamboomy.cjr.dto;
import org.bamboomy.cjr.model.FactCode;
import org.bamboomy.cjr.model.FactCodeType;
import org.bamboomy.cjr.utility.FullDateUtil;
import org.bamboomy.cjr.utility.Locales;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.util.Assert;
import java.util.*;
#Getter
#Setter
#ToString
public class FactCodeDto extends TreeNodeValue {
private String cdFact;
private String cdFactSuffix;
private Boolean isSupplementCode;
private Boolean isTitleCode;
private Boolean mustBeFollowed;
private Date activeFrom;
private Date activeTo;
private Boolean isCode;
private Long idFact;
private Long idParent;
private String type;
Map<Locale, String> description = new HashMap<Locale, String>(3);
public FactCodeDto() {
}
public FactCodeDto(String prefix, String suffix) {
super();
this.cdFact = prefix;
this.cdFactSuffix = suffix;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
this.idFact = idFact;
this.idParent = idParent;
this.isCode = isCode;
this.isTitleCode = isTitleCode;
this.activeFrom = from;
this.activeTo = to;
if (descriptions != null) {
this.description = descriptions;
}
this.type = type;
}
public FactCodeDto(FactCode fc) {
this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode());
}
public String formatCode() {
return FactCode.formatCode(cdFact, cdFactSuffix);
}
public boolean isActive() {
Date now = new Date(System.currentTimeMillis());
return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo);
}
public void setDescFr(String s) {
description.put(Locales.FRENCH, s);
}
public void setDescNl(String s) {
description.put(Locales.DUTCH, s);
}
public void setDescDe(String s) {
description.put(Locales.GERMAN, s);
}
/**
* public String toString() {
* StringBuilder sb = new StringBuilder();
* sb.append(getIdFact() + ": ")
* .append(getIdParent() + ": ")
* .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal "))
* .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed "));
* return sb.toString();
* }
*/
public Map<Locale, String> getDescription() {
return description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
String fullCode = formatCode();
result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FactCodeDto other = (FactCodeDto) obj;
return formatCode().equals(other.formatCode());
}
#Override
public boolean isChildOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isChild = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact());
}
}
return isChild;
}
#Override
public boolean isBrotherOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isBrother = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent());
}
}
return isBrother;
}
#Override
public boolean isParentOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isParent = false;
if (value instanceof FactCodeDto) {
isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent());
}
return isParent;
}
#Override
public int compareTo(TreeNodeValue to) {
if (to instanceof FactCodeDto) {
return formatCode().compareTo(((FactCodeDto) to).formatCode());
} else return 1;
}
public String getCode() {
return formatCode();
}
}
I found that AliasToBean has changed in Hibernate 5. For me adding getter for my field fixed the problem.
This exception occurs when the setters and getters are not mapped correctly to the column names.
Make sure you have the correct getters and setters for the query(Correct names and correct datatypes).
Read more about it here:
http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/
I do some investigation on this question. The problem is that Hibernate converts aliases for column names to upper case — cdFact becomesCDFACT.
Read for a more deeply explanation and workaround here:
mapping Hibernate query results to custom class?
In the end it wasn't so hard to find a solution,
I just created my own (custom) ResultTransformer and specified that in the setResultTransformer method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer());
//return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
the code of the custom result transformer:
package org.bamboomy.cjr.dao.factcode;
import org.bamboomy.cjr.dto.FactCodeDto;
import java.util.Date;
import java.util.List;
/**
* Created by a162299 on 3-11-2015.
*/
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
FactCodeDto result = new FactCodeDto();
for (int i = 0; i < objects.length; i++) {
setField(result, strings[i], objects[i]);
}
return result;
}
private void setField(FactCodeDto result, String string, Object object) {
if (string.equalsIgnoreCase("cdFact")) {
result.setCdFact((String) object);
} else if (string.equalsIgnoreCase("cdFactSuffix")) {
result.setCdFactSuffix((String) object);
} else if (string.equalsIgnoreCase("isSupplementCode")) {
result.setIsSupplementCode((Boolean) object);
} else if (string.equalsIgnoreCase("isTitleCode")) {
result.setIsTitleCode((Boolean) object);
} else if (string.equalsIgnoreCase("mustBeFollowed")) {
result.setMustBeFollowed((Boolean) object);
} else if (string.equalsIgnoreCase("activeFrom")) {
result.setActiveFrom((Date) object);
} else if (string.equalsIgnoreCase("activeTo")) {
result.setActiveTo((Date) object);
} else if (string.equalsIgnoreCase("descFr")) {
result.setDescFr((String) object);
} else if (string.equalsIgnoreCase("descNl")) {
result.setDescNl((String) object);
} else if (string.equalsIgnoreCase("descDe")) {
result.setDescDe((String) object);
} else if (string.equalsIgnoreCase("type")) {
result.setType((String) object);
} else if (string.equalsIgnoreCase("idFact")) {
result.setIdFact((Long) object);
} else if (string.equalsIgnoreCase("idParent")) {
result.setIdParent((Long) object);
} else if (string.equalsIgnoreCase("isCode")) {
result.setIsCode((Boolean) object);
} else {
throw new RuntimeException("unknown field");
}
}
#Override
public List transformList(List list) {
return list;
}
}
in hibernate 3 you could set Aliasses to queries but you can't do that anymore in hibernate 5 (correct me if I'm wrong) hence the aliasToBean is something you only can use when actually using aliasses; which I didn't, hence the exception.
Im my case :
=> write sql query and try to map result to Class List
=> Use "Transformers.aliasToBean"
=> get Error "cannot be cast to java.util.Map"
Solution :
=> just put \" before and after query aliases
ex:
"select first_name as \"firstName\" from test"
The problem is that Hibernate converts aliases for column names to upper case or lower case
I solved it by defining my own custom transformer as given below -
import org.hibernate.transform.BasicTransformerAdapter;
public class FluentHibernateResultTransformer extends BasicTransformerAdapter {
private static final long serialVersionUID = 6825154815776629666L;
private final Class<?> resultClass;
private NestedSetter[] setters;
public FluentHibernateResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
createCachedSetters(resultClass, aliases);
Object result = ClassUtils.newInstance(resultClass);
for (int i = 0; i < aliases.length; i++) {
setters[i].set(result, tuple[i]);
}
return result;
}
private void createCachedSetters(Class<?> resultClass, String[] aliases) {
if (setters == null) {
setters = createSetters(resultClass, aliases);
}
}
private static NestedSetter[] createSetters(Class<?> resultClass, String[] aliases) {
NestedSetter[] result = new NestedSetter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
result[i] = NestedSetter.create(resultClass, aliases[i]);
}
return result;
}
}
And used this way inside the repository method -
#Override
public List<WalletVO> getWalletRelatedData(WalletRequest walletRequest,
Set<String> requiredVariablesSet) throws GenericBusinessException {
String query = getWalletQuery(requiredVariablesSet);
try {
if (query != null && !query.isEmpty()) {
SQLQuery sqlQuery = mEntityManager.unwrap(Session.class).createSQLQuery(query);
return sqlQuery.setResultTransformer(new FluentHibernateResultTransformer(WalletVO.class))
.list();
}
} catch (Exception ex) {
exceptionThrower.throwDatabaseException(null, false);
}
return Collections.emptyList();
}
It worked perfectly !!!
Try putting Column names and field names both in capital letters.
This exception occurs when the class that you specified in the AliasToBeanResultTransformer does not have getter for the corresponding columns. Although the exception details from the hibernate are misleading.
I am trying to implement a crossfield validation (JSR-303) with a custom annotation on class level. However the isValid method is not called (but the initialize method).
So my question is: Why is the isValid method not being called for this class level validator? Defining it on property level works!
I tried it on JBoss AS 7 and Websphere AS 8.
Here is the code and a JUnit test (which works)
Test.java
public class Test {
#org.junit.Test
public void test() throws ParseException {
Person person = new Person();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMDD");
person.setPartyClosingDateFrom(new Date());
person.setPartyClosingDateTo(sdf.parse("20120210"));
Set<ConstraintViolation<Person>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(person);
for(ConstraintViolation<Person> violation : violations) {
System.out.println("Message:- " + violation.getMessage());
}
}
}
DateCompare.java
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Target({ TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy = DateCompareValidator.class)
#Documented
public #interface DateCompare {
/** First date. */
String firstDate();
/** Second date. */
String secondDate();
Class<?>[] constraints() default {};
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "totally wrong, dude!";
DateValidator.DateComparisonMode matchMode() default
DateValidator.DateComparisonMode.EQUAL;
}
DateCompareValidator.java
public class DateCompareValidator implements ConstraintValidator<DateCompare, Object> {
/** describes the mode the validator should use**/
private DateValidator.DateComparisonMode comparisonMode;
/** The first date field name. */
private String firstDateFieldName;
/** The second date field name. */
private String secondDateFieldName;
/** the message to be used **/
private String messageKey = "failure";
/**
* Initialize.
*
* This method is used to set the parameters ans is REQUIRED even if you don't use any parameters
*
* #param constraintAnnotation the constraint annotation
*/
#Override
public void initialize(final DateCompare constraintAnnotation) {
this.comparisonMode = constraintAnnotation.matchMode();
this.firstDateFieldName = constraintAnnotation.firstDate();
this.secondDateFieldName = constraintAnnotation.secondDate();
}
/**
* Checks if it is valid.
*
* #param target the target
* #param context the context
* #return true, if is valid
*/
#Override
public boolean isValid(final Object target, final ConstraintValidatorContext context) {
boolean isValid = true;
final Date valueDate1 = DateCompareValidator.getPropertyValue(Date.class, this.firstDateFieldName, target);
final Date valueDate2 = DateCompareValidator.getPropertyValue(Date.class, this.secondDateFieldName, target);
if (isValid) {
isValid = DateValidator.isValid(valueDate1, valueDate2, this.comparisonMode);
} else {
// at this point comparisonMode does not fit tp the result and we have to
// design an error Message
final ResourceBundle messageBundle = ResourceBundle.getBundle("resources.messages");
final MessageFormat message = new MessageFormat(messageBundle.getString(this.messageKey));
final Object[] messageArguments = { messageBundle.getString(this.messageKey + "." + this.comparisonMode) };
// replace the default-message with the one we just created
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message.format(messageArguments)).addConstraintViolation();
isValid = false;
}
return isValid;
}
public static <T> T getPropertyValue(final Class<T> requiredType, final String propertyName, final Object instance) {
if (requiredType == null) {
throw new IllegalArgumentException("Invalid argument. requiredType must NOT be null!");
}
if (propertyName == null) {
throw new IllegalArgumentException("Invalid argument. PropertyName must NOT be null!");
}
if (instance == null) {
throw new IllegalArgumentException("Invalid argument. Object instance must NOT be null!");
}
T returnValue = null;
try {
final PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, instance.getClass());
final Method readMethod = descriptor.getReadMethod();
if (readMethod == null) {
throw new IllegalStateException("Property '" + propertyName + "' of " + instance.getClass().getName()
+ " is NOT readable!");
}
if (requiredType.isAssignableFrom(readMethod.getReturnType())) {
try {
final Object propertyValue = readMethod.invoke(instance);
returnValue = requiredType.cast(propertyValue);
} catch (final Exception e) {
e.printStackTrace(); // unable to invoke readMethod
}
}
} catch (final IntrospectionException e) {
throw new IllegalArgumentException("Property '" + propertyName + "' is NOT defined in "
+ instance.getClass().getName() + "!", e);
}
return returnValue;
}
DateValidator.java
public class DateValidator {
/**
* The Enum DateComparisonMode.
*
* Determins which Type of validation is used
*/
public enum DateComparisonMode {
/** the given Date must be BEFORE the referenced Date */
BEFORE,
/** the given Date must be BEFORE_OR_EQUAL the referenced Date */
BEFORE_OR_EQUAL,
/** the given Date must be EQUAL the referenced Date */
EQUAL,
/** the given Date must be AFTER_OR_EQUAL the referenced Date */
AFTER_OR_EQUAL,
/** the given Date must be AFTER the referenced Date */
AFTER;
}
/**
* Compare 2 Date Values based on a given Comparison Mode.
*
* #param baseDate the base date
* #param valuationDate the valuation date
* #param comparisonMode the comparison mode
* #return true, if is valid
*/
public static boolean isValid(final Date baseDate, final Date valuationDate, final DateComparisonMode comparisonMode) {
// Timevalue of both dates will be set to 00:00:0000
final Date compValuationDate = DateValidator.convertDate(valuationDate);
final Date compBaseDate = DateValidator.convertDate(baseDate);
// compare the values
final int result = compValuationDate.compareTo(compBaseDate);
// match the result to the comparisonMode and return true
// if rule is fulfilled
switch (result) {
case -1:
if (comparisonMode == DateComparisonMode.BEFORE) {
return true;
}
if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
return true;
}
break;
case 0:
if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
return true;
}
if (comparisonMode == DateComparisonMode.EQUAL) {
return true;
}
if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
return true;
}
break;
case 1:
if (comparisonMode == DateComparisonMode.AFTER) {
return true;
}
if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
return true;
}
break;
default:
return false; // should not happen....
}
return false;
}
/**
* Convert date.
*
* sets the time Value of a given Date filed to 00:00:0000
*
* #param t the t
* #return the date
*/
private static Date convertDate(final Date t) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(t);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return (calendar.getTime());
}
Especially the property retrieval was taken from this post question
JSF 2.0 doesn't call class level validation constraints.
From JSF validation:
JSF 2 provides built-in integration with JSR-303 constraints. When you
are using bean validation in your application, JSF automatically uses
the constraints for beans that are referenced by UIInput values.
You have to call it manually, or you can try Seam Faces which has an extension <f:validateBean>
Goal :
set value for the given java bean at run time and generate JSON Object or JSON array.
the above is my goal and i have tried some thing like the below :
package com.hexgen.tools;
import java.lang.reflect.Method;
import com.google.gson.Gson;
public class ConvertPOJOToJSON {
public Object creatJSONObject(String className) throws IllegalArgumentException, IllegalAccessException, InstantiationException, Exception {
Class<?> objectClass = null;
Object clsObject =null;
try {
objectClass = Class.forName(className);
clsObject = objectClass.newInstance();
for(Method m : objectClass.getMethods())
if (m.getName().startsWith("set") && m.getParameterTypes().length == 1 && m.getModifiers()==23)
m.invoke(clsObject, "myValue");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return clsObject;
}
public static void main(String[] args) {
Gson gson = new Gson();
ConvertPOJOToJSON pojoToJSON = new ConvertPOJOToJSON();
try {
System.out.println("JSON OBJECT : "+gson.toJson(pojoToJSON.creatJSONObject("com.hexgen.ro.request.CreateRequisitionRO")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
The Output of the above class :
JSON OBJECT : {"isAllocable":false}
there are many fields in the class i gave com.hexgen.ro.request.CreateRequisitionRO but only one boolean value is set to false and returns the value.
i have some constant value to set for the fields say if the field type is Integer than set some default integer value like so
EDIT :
I have created a enum like the following :
package com.hexgen.tools;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.joda.time.LocalDate;
public enum DefaultParamValues {
STRING("HEXGEN"),
INTEGER(123),
DATE(new LocalDate()),
BOOLEAN(true),
LONGVALUE(123123),
BIGDECIMAL(new BigDecimal("100000"));
private String defaultString;
private int defaultInteger;
private LocalDate defaultDate;
private boolean defaultBoolean;
private long defaultLong;
private BigDecimal defaultBigDecimal;
private DefaultParamValues(String strDefaultValue) {
defaultString = strDefaultValue;
}
private DefaultParamValues(int intDefaultValue) {
defaultInteger = intDefaultValue;
}
private DefaultParamValues(LocalDate dateDefaultValue) {
defaultDate = dateDefaultValue;
}
private DefaultParamValues(boolean booleanDefaultValue) {
defaultBoolean = booleanDefaultValue;
}
private DefaultParamValues(long longDefaultValue) {
defaultLong = longDefaultValue;
}
private DefaultParamValues(BigDecimal bigIntegerDefaultValue) {
defaultBigDecimal = bigIntegerDefaultValue;
}
public String getDefaultString() {
return defaultString;
}
public int getDefaultInt() {
return defaultInteger;
}
public LocalDate getDefaultDate() {
return defaultDate;
}
public boolean getDefaultBoolean() {
return defaultBoolean;
}
public long getDefaultLong() {
return defaultLong;
}
public BigDecimal getDdefaultBigDecimal() {
return defaultBigDecimal;
}
}
created one more method like the following :
public Object creatObjectWithDefaultValue(String className) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
DefaultParamValues defaultParamValues = null;
Class<?> objectClass = null;
Object clsObject =null;
try {
objectClass = Class.forName(className);
clsObject = objectClass.newInstance();
Field[] fields = objectClass.getDeclaredFields();
for(Field f:fields){
if(!f.isAccessible()){
f.setAccessible(true);
Class<?> type = f.getType();
if(! Modifier.isFinal(f.getModifiers()) && type.equals(Integer.class)){
f.set(clsObject, defaultParamValues.INTEGER);
} else if( !Modifier.isFinal(f.getModifiers()) && type.equals(java.math.BigDecimal.class)){
f.set(clsObject, defaultParamValues.BIGDECIMAL);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(org.joda.time.LocalDate.class)){
f.set(clsObject,defaultParamValues.DATE);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(boolean.class)){
f.set(clsObject, defaultParamValues.BOOLEAN);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(java.lang.String.class)){
f.set(clsObject, defaultParamValues.STRING);
}
else if(! Modifier.isFinal(f.getModifiers()) && type.equals(long.class)){
f.set(clsObject, defaultParamValues.LONGVALUE);
}
//f.setAccessible(false);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return clsObject;
}
to set the default values but i get the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.math.BigDecimal field com.hexgen.ro.request.CreateRequisitionRO.transSrlNo to com.hexgen.tools.DefaultParamValues
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at com.hexgen.tools.JsonConverter.creatObjectWithDefaultValue(JsonConverter.java:93)
at com.hexgen.tools.JsonConverter.main(JsonConverter.java:201)
Please help me to find the solution.
Best Regards
If your looking for a lightweight library which can do this and more including allowing you to do your own filtering to find Methods/Fields. I wrote an open source library which has no 3rd party dependencies and is available on Maven Central.
Checkout https://github.com/gondor/reflect
As for your issue it appears your setting the "Enum" constant and not the inner value of the enum. Wouldn't it DefaultParamValues.BIGDECIMAL.getDdefaultBigDecimal()