'Why method print() of my class CustomDateFormatter using with my custom spring annotation is never called?
I have a issue with creation of custom annotation in springboot application: I've got a form with few fields with datepicker. Dates must have to be parsed in 2 formats "dd/MM/yyyy" or "yyyy/MM/dd". To achieve that , as annotation @DateTimeFormat on a field of Entity only use one pattern, I decided to create my custom DateFormatter to be able to have my 2 formats:
public class CustomDateFormatter implements Formatter<Date> {
final String DATE_PATTERN_FR = "^(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/([0-9]{4})$";
final String DATE_PATTERN_EN = "^([0-9]{4})/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$";
final Pattern dateEnPattern = Pattern.compile(DATE_PATTERN_EN);
final Pattern dateFrPattern = Pattern.compile(DATE_PATTERN_FR);
public class DateFormatRegex {
private String formatPattern;
private String regexPattern;
private Locale locale;
public DateFormatRegex(String format, String regex, Locale locale) {
this.formatPattern = format;
this.regexPattern = regex;
this.locale = locale;
}
public String getFormatPattern() {
return formatPattern;
}
public void setFormatPattern(String formatPattern) {
this.formatPattern = formatPattern;
}
public String getRegexPattern() {
return regexPattern;
}
public void setRegexPattern(String regexPattern) {
this.regexPattern = regexPattern;
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public SimpleDateFormat getSimpleDateFormat() {
return new SimpleDateFormat(this.formatPattern);
}
public Pattern getPattern() {
return Pattern.compile(this.regexPattern);
}
}
private List<DateFormatRegex> patterns;
public CustomDateFormatter(List<DateFormatRegex> patterns) {
this.patterns = patterns;
}
public CustomDateFormatter() {
this.patterns = new ArrayList<>();
this.patterns.add(new DateFormatRegex("dd/MM/yyyy", DATE_PATTERN_FR, new Locale("fr")));
this.patterns.add(new DateFormatRegex("yyyy/MM/dd", DATE_PATTERN_EN, new Locale("en")));
};
@Override
public final String print(Date date, Locale locale) {
if (date == null) {
return "";
}
for (DateFormatRegex dfr : patterns) {
System.out.println(dfr.getLocale());
System.out.println(locale.getLanguage());
if (locale.getLanguage().equals(dfr.getLocale().toString())) {
try {
String dateString = dfr.getSimpleDateFormat().format(date);
System.out
.println(("PRINT ==> date :" + date.toString() + " formatString: " + dfr.getFormatPattern()
+ " date formated : " + dateString));
return dateString;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
@Override
public Date parse(String text, Locale locale) throws ParseException {
if (text == null || text.length() == 0) {
return null;
}
for (DateFormatRegex dfr : patterns) {
if (dfr.getPattern().matcher(text).matches()) {
try {
Date date = dfr.getSimpleDateFormat().parse(text);
System.out.println("PARSE ==> date :" + date.toString() + " formatString: " + dfr.getFormatPattern()
+ " date sous forme text: " + text);
return date;
} catch (ParseException e) {
}
}
}
return null;
}
After that, I Implement AnnotationFormatterFactory as mentioned at Spring 3 Field Formatting:
public class DateFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<CustomDateFormat> {
@Override
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{java.util.Date.class}));
}
@Override
public Printer<Date> getPrinter(CustomDateFormat annotation, Class<?> fieldType) {
return getCustomDateFormatter(annotation,fieldType);
}
@Override
public Parser<Date> getParser(CustomDateFormat annotation, Class<?> fieldType) {
return getCustomDateFormatter(annotation, fieldType);
}
private CustomDateFormatter getCustomDateFormatter(CustomDateFormat annotation, Class<?> fieldType) {
return new CustomDateFormatter();
}
}
And override method addFormatter() in my class MVCConfiguration:
@Configuration
@ComponentScan
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateFormatAnnotationFormatterFactory factory = new DateFormatAnnotationFormatterFactory();
registry.addFormatterForFieldAnnotation(factory);
} }
Finally, I create my custom annotation and use it in Entity actionTracking on field Date creationDate... My problem is that method parse() of my CustomDateFormatter is correctly used : I retrieve my dates in one of two patterns according locale but when I want to display in front-end( using thymeleaf or js after request ajax) date of my entity , method print() is never called and i saw the date in this pattern "yyyy-MM-dd". I don't understand why parsing is correct and not format. May be I miss something to print date in correct pattern. (Just below : Entity, controller, service) Can anybody help me please .Thanks a lot.
@Entity
@Table(name = "actionTracking")
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class ActionTracking implements Comparable<Object> {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@NotNull
private int name;
private Boolean type;
private String state;
private String priority;
private String theme;
private String origin;
@Column(length = 10000)
@Size(min = 1, message = "Ce champ est obligatoire.")
private String designation;
private String responsible;
@Temporal(TemporalType.DATE)
@CustomDateFormat
@NotNull(message = "Ce champ est obligatoire.")
private Date creationDate;
...
controller
@GetMapping("/getactions")
public ResponseEntity<Object> getActions(@PathVariable(value = "missionId") long missionId,
Authentication authentication) {
...
List<ActionTracking> linkedActions = actionTrackingService.findActionTracking(mission);
List<HashMap<Object, Object>> actions = new ArrayList<>();
if (linkedActions != null && !linkedActions.isEmpty()) {
for (ActionTracking actionTracking : linkedActions) {
actions.add(actionTrackingService.toMapV2(actionTracking, user.getLang()));
}
}
HashMap<String, Object> finalResult = new HashMap<>();
finalResult.put("actions", actions);
return new ResponseEntity<Object>(finalResult, HttpStatus.OK);
@PostMapping("/add")
public ResponseEntity<Object> addActionTracking(Model model,
@PathVariable(value = "missionId") long missionId,
// @PathVariable(value = "objectId") long objectId,
@RequestParam(value = "reference") String reference,
@RequestParam(value = "linkedActions") ArrayList<ActionTracking> linkedActions,
@RequestParam(value = "riskId") Optional<Long> linkedRiskId,
@RequestParam(value = "SatisfactionId") Optional<Long> linkedSatisfactionId,
@Valid ActionTracking actionTracking,
BindingResult bindingResult, Authentication authentication) {...
service
@Service
public class ActionTrackingService {
...
public HashMap<Object, Object> toMapV2(ActionTracking actionTracking, String lang) {
Locale locale = new Locale(lang);
HashMap<Object, Object> result = new HashMap<>();
result.put("id", actionTracking.getId());
result.put("name", actionTracking.getName());
...
result.put("creationDate", actionTracking.getCreationDate());
result.put("initialDate", actionTracking.getInitialDate());
result.put("revisedDate", actionTracking.getRevisedDate());
return result;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|