I hava a POJO object with one BigDecimal field sum.
In controller I add this POJO object as form like this:
MyForm form = new MyForm();
model.addAttribute("command", form);
My jsp:
<form:input path="sum" size="27"/>
In controller i add initbinder:
binder.registerCustomEditor(BigDecimal.class, new SumEditor());
Part of my SumEditor class:
#Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(parseMoney(text));
}
private BigDecimal parseMoney(String str) {
try {
return new BigDecimal(str);
} catch (Exception e) {
logger.error("error", e);
}
return null;
}
But in JSP view I see (in input field): |null________|
How fix this? I need: |___________|
You should simply override getText method of SumEditor to have it return an empty string ("") for a null value :
#Override
public String getAsText() {
if (getValue == null) {
return "";
}
BigDecimal val = (BigDecimal) getValue();
return val.toStr(); // or whatever conversion you need
}
Related
I'm trying to validate the information, user is giving at the registration. One of the fields contains the mailadress, which should be validated by looking in the database to confirm, it doesn't exist yet.
Problem is, that if i type an existing mailadress, it will give back a NonUniqueResultException, but also does store the new user with the duplicate mailadress in the database. Don't understand this, beacuse in the JSF-lifecycle after validation fails, it shouldn't go on to the invoke application phase, right?
Here's my code:
mail field in register formular
<b:inputText id="mail" required="true"
requiredMessage="Bitte geben Sie Ihre E-Mail-Adresse an!"
label="E-Mail" placeholder="name#example.com" value="#{registrierenManagedBean.nutzer.mail}">
<f:validator validatorId="mailValidatorRegistrieren"/>
<b:messages for="mail"/>
</b:inputText>
my custom validator
#FacesValidator("mailValidatorRegistrieren")
public class MailValidatorRegistrieren implements Validator {
#EJB
private DAO dao;
private String mail;
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
#Override
public void validate(FacesContext facesContext, UIComponent uiComponent, Object o) throws ValidatorException {
mail = (String)o;
boolean matchesPattern = EMAIL_PATTERN.matcher(mail).find();
if(!matchesPattern)
{
throw new ValidatorException((new FacesMessage("Invalid mail")));
}
if(mail.isEmpty()) {
return;
} else if(validateNutzer(mail)){
throw new ValidatorException(new FacesMessage("mail alredy used"));
} else{
return;
}
}
private boolean validateNutzer(String mail) {
try {
Nutzer n = dao.findNutzerByMail(mail);
return n.getMail().equals(mail);
} catch (NullPointerException e) {
return false;
}
}
}
and the "findNutzerByMail"-method from my DAO
public Nutzer findNutzerByMail(String mail) {
try {
return em.createNamedQuery("findNutzerByMail", Nutzer.class)
.setParameter("mail", mail)
.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
When the date format is not correct (for example when I manually post 13,02,2018 instead of 13.02.2018 and also other incorrect dates such as 13.02.999) the app crashes. How can I fix it? (the manual input is important, i can`t just disable it).
XHTML:
<rich:calendar enableManualInput="true" datePattern="dd.MM.yyyy"
value="#{myBean.data.myDate}">
<f:converter converterId="mydate"/>
</rich:calendar>
Converter:
#FacesConverter("mydate")
public class LocalDateConverter implements Converter {
private static final DateTimeFormatter formatter;
static {
formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
formatter.withLocale(new Locale("ru"));
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return LocalDate.parse(value, formatter);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
} else if (value instanceof LocalDate) {
return ((LocalDate) value).format(formatter);
} else if (value instanceof LocalDateTime) {
return ((LocalDateTime) value).format(formatter);
} else {
throw new IllegalArgumentException("Value is not java.time.LocaleDate");
}
}
Converters should throw a ConverterException which can contain a FacesMessage. This message can be displayed on your XHTML page, near the input component that caused the exception using <h:message for="inputComponentId"/>.
The problem occurs in your getAsObject method. There you should catch the DateTimeParseException exception and throw a ConverterException:
try {
return LocalDate.parse(value, formatter);
}
catch (DateTimeParseException ex) {
throw new ConverterException(new FacesMessage("Invalid date: " + value));
}
See also:
https://docs.oracle.com/javaee/7/tutorial/jsf-custom010.htm
How to use java.time.ZonedDateTime / LocalDateTime in p:calendar
You don't need converter at all. Simply include label attribute in rich:calendar component and let system figure out if value is correct. Example:
<h:outputLabel for="programStartDate" value="#{msg.programStartDate}" />
<rich:calendar id="programStartDate" value="#{program.programStartDate}"
label="#{msg.programStartDate}" inputStyle="width: 100px;"
datePattern="#{referenceData.defaultDatePattern}"
timeZone="#{referenceData.timezone}"
enableManualInput="true" popup="true" required="true" />
use a try catch and catch the exception so it doesn't crash but continue without allowing the exception to crash your program
#FacesConverter("mydate")
public class LocalDateConverter implements Converter
{
private static final DateTimeFormatter formatter;
static {
formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
formatter.withLocale(new Locale("ru"));
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
return LocalDate.parse(value, formatter);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
try
{
if (value == null)
{
return "";
}
else if (value instanceof LocalDate) {
return ((LocalDate)value).format(formatter);
} else if (value instanceof LocalDateTime) {
return ((LocalDateTime)value).format(formatter);
} else {
throw new IllegalArgumentException("Value is not java.time.LocaleDate");
}
}
catch (Exception)
{
return "SOME DEFAULT DATE";
}
}
}
I'm trying to add a new field to request's body, in a Zuul Pre-filter.
I'm using one of the Neflix's Zuul sample projects from here, and my filter's implementation is very similar to UppercaseRequestEntityFilter from this sample.
I was able to apply a transformation such as uppercase, or even to completely modify the request, the only inconvenient is that I'm not able to modify the content of body's request that has a length more than the original length of the body's request.
This is my filter's implementation:
#Component
public class MyRequestEntityFilter extends ZuulFilter {
public String filterType() {
return "pre";
}
public int filterOrder() {
return 10;
}
public boolean shouldFilter() {
RequestContext context = getCurrentContext();
return true;
}
public Object run() {
try {
RequestContext context = getCurrentContext();
InputStream in = (InputStream) context.get("requestEntity");
if (in == null) {
in = context.getRequest().getInputStream();
}
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
body = body.replaceFirst("qqq", "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");
// body = body.toUpperCase();
context.set("requestEntity", new ServletInputStreamWrapper(body.getBytes("UTF-8")));
}
catch (IOException e) {
rethrowRuntimeException(e);
}
return null;
}
}
This is the request that I'm doing:
This is the response that I'm receiving:
I was able to obtain what I wanted, using the implementation of PrefixRequestEntityFilter, from sample-zuul-examples:
#Component
public class MyRequestEntityFilter extends ZuulFilter {
public String filterType() {
return "pre";
}
public int filterOrder() {
return 10;
}
public boolean shouldFilter() {
RequestContext context = getCurrentContext();
return true;
}
public Object run() {
try {
RequestContext context = getCurrentContext();
InputStream in = (InputStream) context.get("requestEntity");
if (in == null) {
in = context.getRequest().getInputStream();
}
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
body = body.replaceFirst("qqq", "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");
byte[] bytes = body.getBytes("UTF-8");
context.setRequest(new HttpServletRequestWrapper(getCurrentContext().getRequest()) {
#Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(bytes);
}
#Override
public int getContentLength() {
return bytes.length;
}
#Override
public long getContentLengthLong() {
return bytes.length;
}
});
}
catch (IOException e) {
rethrowRuntimeException(e);
}
return null;
}
}
I'm trying to get the fallback solution working on mobile but having some issues.
I've the following jsp structure
views
-mobile
--about.jsp
-tablet
--about.jsp
--intermediary.jsp
about.jsp
intermediary.jsp
Currently I don't have a intermediary.jsp in the mobile but I have it in the fallback directory. The resolveViewName within the AbstractDeviceDelegatingViewResolver only fires if the view is null.
public View resolveViewName(String viewName, Locale locale) throws Exception {
String deviceViewName = getDeviceViewName(viewName);
View view = delegate.resolveViewName(deviceViewName, locale);
if (enableFallback && view == null) {
view = delegate.resolveViewName(viewName, locale);
}
if (logger.isDebugEnabled() && view != null) {
logger.deb
The problem I'm having is I can't find any viewResolver to return null. The InternalResourceViewResolver doesn't return null and the UrlBasedViewResolver always returns the view name of /mobile/intermediary.jsp which doesn't exist which in turn throws a 404. Anyone know which resolver I should be using for the fallback solution to work?
Thanks,
look at the source you will find the answer:
public abstract class AbstractUrlBasedView{
...
public boolean checkResource(Locale locale) throws Exception {
return true;
}
...
}
public class InternalResourceView extends AbstractUrlBasedView {
//!!not override the checkResource method!!
}
public class FreeMarkerView extends AbstractTemplateView {
...
#Override
public boolean checkResource(Locale locale) throws Exception {
try {
// Check that we can get the template, even if we might subsequently get it again.
getTemplate(getUrl(), locale);
return true;
}
catch (FileNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No FreeMarker view found for URL: " + getUrl());
}
return false;
}
catch (ParseException ex) {
throw new ApplicationContextException(
"Failed to parse FreeMarker template for URL [" + getUrl() + "]", ex);
}
catch (IOException ex) {
throw new ApplicationContextException(
"Could not load FreeMarker template for URL [" + getUrl() + "]", ex);
}
}
...
}
so that you may be extends InternalResourceView like below:
public class MyInternalResourceView extends InternalResourceView {
private static final boolean SEP_IS_SLASH = File.separatorChar == '/';
protected File getTemplate(String name, Locale locale) throws IOException {
File source;
if(getServletContext()!=null){
name = getServletContext().getRealPath("")+name;
source = new File( SEP_IS_SLASH ? name : name.replace('/',
File.separatorChar));
}
else{
source = new File( SEP_IS_SLASH ? name : name.replace('/',
File.separatorChar));
}
if (!source.isFile()) {
return null;
}
return source;
}
#Override
public boolean checkResource(Locale locale) throws Exception {
try {
// Check that we can get the template, even if we might subsequently
// get it again.
return getTemplate(getUrl(), locale)!=null;
} catch (IOException ex) {
return false;
}
}
}
and in viewResolver set your view class
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:viewClass="com.xxxx.MyInternalResourceView" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" p:contentType="text/html;charset=UTF-8" />
Don't want to over-complicate the issue, but I think I need to post all the code that's hooked into this error.
Using MvcMailer and introduced a separate Send mechanism (for use with Orchard CMS' own EMail).
The MvcMailer Code:
1) AskUsMailer.cs:
public class AskUsMailer : MailerBase, IAskUsMailer
{
public AskUsMailer()
: base()
{
//MasterName = "_Layout";
}
public virtual MvcMailMessage EMailAskUs(AskUsViewModel model)
{
var mailMessage = new MvcMailMessage { Subject = "Ask Us" };
ViewData.Model = model;
this.PopulateBody(mailMessage, viewName: "EMailAskUs");
return mailMessage;
}
}
2) IAskUsMailer.cs:
public interface IAskUsMailer : IDependency
{
MvcMailMessage EMailAskUs(AskUsViewModel model);
}
3) AskUsController.cs: (GETTING NULL REFERENCE ERROR BELOW)
[Themed]
public ActionResult Submitted()
{
//This is the new call (see new code below):
//Note: Debugging steps through eMailMessagingService,
//then shows the null reference error when continuing to
//SendAskUs
eMailMessagingService.SendAskUs(askUsData);
//Below is normal MvcMailer call:
//AskUsMailer.EMailAskUs(askUsData).Send();
return View(askUsData);
}
Note: askUsData is defined in a separate block in the controller:
private AskUsViewModel askUsData;
protected override void OnActionExecuting(ActionExecutingContext
filterContext)
{
var serialized = Request.Form["askUsData"];
if (serialized != null) //Form was posted containing serialized data
{
askUsData = (AskUsViewModel)new MvcSerializer().
Deserialize(serialized, SerializationMode.Signed);
TryUpdateModel(askUsData);
}
else
askUsData = (AskUsViewModel)TempData["askUsData"] ??
new AskUsViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext
filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["askUsData"] = askUsData;
}
I did not know how to get my EMailMessagingService.cs (see below) call into the controller, so in a separate block in the controller I did this:
private IEMailMessagingService eMailMessagingService;
public AskUsController(IEMailMessagingService eMailMessagingService)
{
this.eMailMessagingService = eMailMessagingService;
}
I think this is part of my problem.
Now, the new code trying to hook into Orchard's EMail:
1) EMailMessagingServices.cs:
public class EMailMessagingService : IMessageManager
{
private IAskUsMailer askUsMailer;
private IOrchardServices orchardServices;
public EMailMessagingService(IAskUsMailer askUsMailer,
IOrchardServices orchardServices)
{
this.orchardServices = orchardServices;
this.askUsMailer = askUsMailer;
this.Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SendAskUs(AskUsViewModel model)
{
var messageAskUs = this.askUsMailer.EMailAskUs(model);
messageAskUs.To.Add("email#email.com");
//Don't need the following (setting up e-mails to send a copy anyway)
//messageAskUs.Bcc.Add(AdminEmail);
//messageAskUs.Subject = "blabla";
Send(messageAskUs);
}
....
}
The EMailMessagingService.cs also contains the Send method:
private void Send(MailMessage messageAskUs)
{
var smtpSettings = orchardServices.WorkContext.
CurrentSite.As<SmtpSettingsPart>();
// can't process emails if the Smtp settings have not yet been set
if (smtpSettings == null || !smtpSettings.IsValid())
{
Logger.Error("The SMTP Settings have not been set up.");
return;
}
using (var smtpClient = new SmtpClient(smtpSettings.Host,
smtpSettings.Port))
{
smtpClient.UseDefaultCredentials =
!smtpSettings.RequireCredentials;
if (!smtpClient.UseDefaultCredentials &&
!String.IsNullOrWhiteSpace(smtpSettings.UserName))
{
smtpClient.Credentials = new NetworkCredential
(smtpSettings.UserName, smtpSettings.Password);
}
if (messageAskUs.To.Count == 0)
{
Logger.Error("Recipient is missing an email address");
return;
}
smtpClient.EnableSsl = smtpSettings.EnableSsl;
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
messageAskUs.From = new MailAddress(smtpSettings.Address);
messageAskUs.IsBodyHtml = messageAskUs.Body != null &&
messageAskUs.Body.Contains("<") &&
messageAskUs.Body.Contains(">");
try
{
smtpClient.Send(messageAskUs);
Logger.Debug("Message sent to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
catch (Exception e)
{
Logger.Error(e, "An unexpected error while sending
a message to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
}
}
Now, in EMailMessagingService.cs I was getting an error that things weren't being implemented, so I auto-generated the following (don't know if this is part of my error):
public void Send(Orchard.ContentManagement.Records.ContentItemRecord recipient, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Records.ContentItemRecord> recipients, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<string> recipientAddresses, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public bool HasChannels()
{
throw new NotImplementedException();
}
public System.Collections.Generic.IEnumerable<string> GetAvailableChannelServices()
{
throw new NotImplementedException();
}
2) IEMailMessagingServices.cs
public interface IEMailMessagingService
{
MailMessage SendAskUs(AskUsViewModel model);
}
MvcMailer works fine without this addition (outside of Orchard), but I am trying to get everything working within Orchard.
I just cannot figure out what I am doing wrong. Any thoughts?
Sorry for excessive code.
IEmailMessaginService does not implement IDependency, so it can't be found by Orchard as a dependency. That's why it's null.