h:inputSecret redisplay="false" required="false"><s:validateEquality : confirm field either required or not checked at all - seam

I use seam 2.2.0.GA.
My password/confirm fields have redisplay="false" so the current password isn't in html.
validateEquality is in the confirm field.
I want the following behavior: when I create a new entity, both password/confirm fields should be required. When I edit an entity, both fields shouldn't be required, but the equality should be checked in any case. For that I have h:inputSecret required="#{required}" and calculate the param "required".
There're 2 problems:
1) s:validateEquality has the attribute "required" too, but it looks buggy: if I hardcode true or false, it works as expected, but if I use required="#{required}" and during a conversation this param changes, the validator still behaves as if the param hasn't changed.
2) s:validateEquality required="false" doesn't check the equality, if the confirm field is empty.
#{sandboxController.now}
<ui:param name="label" value="password"/>
<ui:param name="labelConfirm" value="confirm password"/>
<ui:param name="message" value="not the same"/>
<ui:param name="id" value="bbb"/>
<ui:param name="redisplay" value="#{sandboxBean.redisplay}"/>
<ui:param name="required" value="#{sandboxBean.required}"/>
<ui:param name="value" value="#{sandboxBean.password}" />
<a4j:form id="personalForm">
<a4j:region>
required: <h:selectBooleanCheckbox value="#{required}">
<a4j:support event="onclick" reRender="passwordpanel" />
</h:selectBooleanCheckbox><br/>
redisplay: <h:selectBooleanCheckbox value="#{redisplay}">
<a4j:support event="onclick" reRender="passwordpanel" />
</h:selectBooleanCheckbox><br/>
</a4j:region>
<a4j:outputPanel id="passwordpanel">
password: #{value}<br/>
<s:decorate styleClass="fieldForm #{formClass}">
<div class="fieldLabel #{labelClass}">
<s:label styleClass="#{invalid?'error':''}" >
#{label}
<s:span styleClass="required" rendered="#{required}">*</s:span>
</s:label>
</div>
<div class="fieldInput">
<s:validateAll>
<h:inputSecret id="#{id}" value="#{value}" required="#{required}" redisplay="#{redisplay}">
</h:inputSecret>
</s:validateAll>
<s:message styleClass="error"/>
</div>
</s:decorate>
<s:decorate styleClass="fieldForm #{formClass}">
<div class="fieldLabel #{labelClass}">
<s:label styleClass="#{invalid?'error':''}" >
#{labelConfirm}
<s:span styleClass="required" rendered="#{required}">*</s:span>
</s:label>
</div>
<div class="fieldInput">
<s:validateAll>
<h:inputSecret value="#{value}" required="#{required}" redisplay="#{redisplay}">
<s:validateEquality for="#{id}" required="#{required}" message="#{message}"/>
</h:inputSecret>
</s:validateAll>
<s:message styleClass="error"/>
</div>
</s:decorate>
</a4j:outputPanel>
<a4j:commandLink value="submit" action="#{sandboxController.getNow}" reRender="personalForm" /><br/>
</a4j:form>
SandboxBean.java :
package org.foo.model;
import java.io.Serializable;
public class SandboxBean implements Serializable {
private static final long serialVersionUID = 1L;
private String password = "abcde";
private boolean required=false;
private boolean redisplay=false;
public void setRequired(boolean required) { this.required = required; }
public boolean isRequired() { return required; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public void setRedisplay(boolean redisplay) { this.redisplay = redisplay; }
public boolean isRedisplay() { return redisplay; }
}
SandboxController.java :
package org.foo.logic.model;
import java.io.Serializable;
import java.util.Date;
import org.foo.model.SandboxBean;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;
#Name("sandboxController")
#Scope(ScopeType.CONVERSATION)
public class SandboxController implements Serializable{
private static final long serialVersionUID = 1L;
#Logger Log log;
#Out(required = false)
SandboxBean sandboxBean;
#Begin(join=true)
#Factory("sandboxBean")
public void initSandBoxBean(){
sandboxBean = new SandboxBean();
}
public Date getNow() {
return new Date();
}
}

Problem #1:
The following code turns your "required" field static, I believe:
<ui:param name="required" value="#{sandboxBean.required}"/>
Problem #2:
http://seamframework.org/Community/CustomValidatorUsingTwoFields
Using a custom validator marked with the appropriate annotation, you can then call the with the custom validator.
#Validator
public class PasswordValidator implements javax.faces.validator.Validator, Serializable{
...
throw new ValidatorException(new FacesMessage("Passwords do not match."));

public class PasswordConverter
implements Converter
{
public static String DONT = "__dontchange__";
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
if (DONT.equals(value) && component instanceof UIOutput) {
return ((UIOutput)component).getValue();
} else {
return value;
}
}
public String getAsString(FacesContext context, UIComponent component, Object value)
{
if (value instanceof String && component instanceof UIOutput && ((String)value).length() > 0) {
return DONT;
} else if (value == null) {
return null;
} else {
return value.toString();
}
}
}

Related

Jackson PropertyFilter not used when serializing XML

I have created a Jackson PropertyFilter an registered it with an XmlMapper, but it is not used to filter properties returned from a Spring #RestController.
I have created and used a Jackson PropertyFilter to filter JSON results produced by an ObjectMapper for a Spring #RestController. I'm trying to enable the same functionality for XML, but can't get it working.
I've tried registering the filter directly on an XmlMapper instance and through a Jackson2ObjectMapperBuilder. In both cases it isn't called.
I've stepped through the code and the XmlBeanSerializer seems to have a reference to the filter, but the filter never gets called.
I created a LogAllPropertyFilter class to just log if the filter is called and no log messages are ever produced.
public class LogAllPropertyFilter extends SimpleBeanPropertyFilter implements PropertyFilter {
private Logger logger = LoggerFactory.getLogger(getClass());
#Override
public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer)
throws Exception {
logger.info(" *** *** serializeAsField {}.{}",
pojo.getClass().getSimpleName(),
writer.getName());
super.serializeAsField(pojo, gen, prov, writer);
}
#Override
public void serializeAsElement(Object elementValue, JsonGenerator gen, SerializerProvider prov,
PropertyWriter writer) throws Exception {
logger.info(" *** *** serializeAsElement {}.{}",
elementValue.getClass().getSimpleName(),
writer.getName());
super.serializeAsElement(elementValue, gen, prov, writer);
}
#SuppressWarnings("deprecation")
#Override
public void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider)
throws JsonMappingException {
logger.info(" *** *** depositSchemaProperty {} (deprecated)",
writer.getName());
super.depositSchemaProperty(writer, propertiesNode, provider);
}
#Override
public void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor,
SerializerProvider provider) throws JsonMappingException {
logger.info(" *** *** depositSchemaProperty {} (deprecated)",
writer.getName());
super.depositSchemaProperty(writer, objectVisitor, provider);
}
}
I'm creating and registering the PropertyFilter like this:
<bean id="logAllFilter" class="calpers.eai.config.auth.jacksonpropertyfilter.LogAllPropertyFilter" />
<bean id="logAllFilterProvider"
class="com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider">
<constructor-arg>
<map>
<entry key="logAllFilter"
value-ref="logAllFilter" />
</map>
</constructor-arg>
</bean>
<bean id="xmlObjectMapper"
class="com.fasterxml.jackson.dataformat.xml.XmlMapper" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="xmlObjectMapper" />
<property name="targetMethod" value="setFilterProvider" />
<property name="arguments" ref="logAllFilterProvider" />
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="xmlObjectMapper" />
<property name="targetMethod" value="disable" />
<property name="arguments" value="WRITE_DATES_AS_TIMESTAMPS" />
</bean>
<!-- indent json - disable this in prod -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="xmlObjectMapper" />
<property name="targetMethod" value="enable" />
<property name="arguments" value="INDENT_OUTPUT" />
</bean>
<bean id="xmlConverter" class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<constructor-arg ref="xmlObjectMapper" />
</bean>
<mvc:annotation-driven>
<mvc:message-converters>
<!-- json works -->
<ref bean="jsonConverter" />
<!-- xml doesn't work -->
<ref bean="xmlConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
The XML output is indented so I know it the XmlMapper instance is getting picked up. However, the PropertyFilter methods are never called. I'm stumped.
The filter won't be applied unless the class is linked to the filter somehow. Typically an annotation is used, but in this case, I need to filter properties on all objects, regardless of their provenance, so we'll use a mix-in on the common base-class of all Java objects:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="xmlObjectMapper" />
<property name="targetMethod" value="addMixIn" />
<property name="arguments">
<list>
<value type="java.lang.Class">java.lang.Object</value>
<value type="java.lang.Class">eai.config.auth.jacksonpropertyfilter.SecurityRoleAwareJacksonMixIn</value>
</list>
</property>
</bean>
With this added to the config, my filters are running on every XML object served from my Spring MVC #RestController.
Here is a handy filter to control access to class properties based on security roles in Spring Security. Enjoy!
package eai.config.auth.jacksonpropertyfilter;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.ldap.userdetails.LdapAuthority;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import eai.config.auth.jacksonpropertyfilter.xml.SecurityRole;
import eai.config.refreshable.Refreshable;
/**
* Filters based on the union of properties a principal can view. In JsonViewConfiguration a user
* with multiple views will be assigned the highest ranked view and only see the properties that are
* included in that view. With SecurityRoleAwareJacksonFilterImpl, the user will see any property they
* have access to based on ALL the groups they are members of. Therefore, it is the union of
* all #JsonView's.
*
* This class should be instantiated as a Spring Bean, probably in the XML config to maximize
* configuration options that avoid a re-compile.
*
* #author TPerry2
*/
public class SecurityRoleAwareJacksonFilterImpl extends SimpleBeanPropertyFilter
implements SecurityRoleAwareJacksonFilter, Refreshable {
private final Logger logger = LoggerFactory.getLogger(
SecurityRoleAwareJacksonFilterImpl.class);
Map<Class<?>, Map<String, Collection<SecurityRole>>> classPropertyRoles =
new HashMap<>();
List<SecurityRoleToClassPropertyReader> securityRoleToClassPropertyReaders =
new ArrayList<>();
private ConcurrentHashMap<String, String> knownUserNoRole =
new ConcurrentHashMap<>();
private ConcurrentHashMap<Class<?>, Set<String>> classPropsWithNoAccess =
new ConcurrentHashMap<>();
/**
* Add mapping for what class properties a LDAP role can view.
*
* #param securityRoleToClassPropertyXmlReaders to obtain mapping data from.
* #throws ClassNotFoundException if the java class can not be found.
* #throws IOException when security role to class property XML files can't be read.
*/
#Override
#Autowired
public void setSecurityRoleToClassPropertyReaders(
List<SecurityRoleToClassPropertyReader> securityRoleToClassPropertyReaders)
throws ClassNotFoundException, IOException {
this.securityRoleToClassPropertyReaders = securityRoleToClassPropertyReaders;
loadClassPropertyRoles();
}
/**
* Method called to determine whether property will be included
* (if 'true' returned) or filtered out (if 'false' returned)
*/
protected boolean include(BeanPropertyWriter writer) {
AnnotatedMember memberToSerialize = writer.getMember();
if (memberToSerialize == null) {
logger.warn("Could not get member to serialize for writer {}",
writer.getClass().getName());
return false;
}
final Class<?> clazz = memberToSerialize.getDeclaringClass();
return include(clazz, writer.getName());
}
/**
* Method called to determine whether property will be included
* (if 'true' returned) or filtered out (if 'false' returned)
*/
protected boolean include(PropertyWriter writer) {
AnnotatedMember memberToSerialize = writer.getMember();
if (memberToSerialize == null) {
logger.warn("Could not get member to serialize for writer {}",
writer.getClass().getName());
return false;
}
final Class<?> clazz = memberToSerialize.getDeclaringClass();
return include(clazz, writer.getName());
}
protected boolean include(
Class<?> clazz,
String propertyName) {
logger.info("Checking {}.{}", clazz.getSimpleName(), propertyName);
final Map<String, Collection<SecurityRole>> propertyLdapRoleMap =
classPropertyRoles.get(clazz);
if (propertyLdapRoleMap != null) {
final Collection<SecurityRole> securityRoles =
propertyLdapRoleMap.get(propertyName);
if (securityRoles != null && securityRoles.size() > 0) {
Authentication auth = getAuthentication();
if (isAuthorized(getGrantedAuthorities(auth), securityRoles)) {
logger.info("allowing {}.{}", clazz.getSimpleName(), propertyName);
return true;
} else {
logUserNoRole(clazz, propertyName, securityRoles, auth);
}
} else {
logPropertyWithNoAccess(clazz, propertyName);
}
} else {
logPropertyWithNoAccess(clazz, "-- all properties --");
}
return false;
}
private void logUserNoRole(
Class<?> clazz,
String propertyName,
Collection<SecurityRole> allowedRoles,
Authentication auth) {
if (!logger.isDebugEnabled()) {
return;
}
String username = (auth == null ? "anonymous" : auth.getName());
final String knownUserNoRoleString = ""
+ clazz.getName() + "." + propertyName + "."
+ username;
boolean known = knownUserNoRole.containsKey(knownUserNoRoleString);
if (!known) {
knownUserNoRole.put(knownUserNoRoleString, "");
logger.debug("User {} does not have valid role for {}.{}. "
+ "Requires one of {}", username, clazz.getName(),
propertyName, allowedRoles);
}
}
private void logPropertyWithNoAccess(Class<?> clazz, String propertyName) {
Set<String> knownPropsWithNoAccess = classPropsWithNoAccess.get(clazz);
if (knownPropsWithNoAccess == null) {
logger.warn("No roles enable access to {}.{}",
clazz.getSimpleName(), propertyName);
knownPropsWithNoAccess = new HashSet<>();
classPropsWithNoAccess.put(clazz, knownPropsWithNoAccess);
}
boolean wasAdded = false;
synchronized (knownPropsWithNoAccess) {
wasAdded = knownPropsWithNoAccess.add(propertyName);
}
if (wasAdded) {
logger.warn("No roles enable access to {}.{}",
clazz.getSimpleName(), propertyName);
}
}
private boolean isAuthorized(
Collection<? extends GrantedAuthority> grantedAuths,
Collection<SecurityRole> securityRoles) {
try {
if (grantedAuths == null) {
return false;
}
for (GrantedAuthority grantedAuth : grantedAuths) {
if (grantedAuth instanceof LdapAuthority) {
LdapAuthority ldapAuth = (LdapAuthority) grantedAuth;
for (SecurityRole secRole : securityRoles) {
if (secRole.distinguishedNameIsAuthorized(
ldapAuth.getDn())) {
return true;
}
if (secRole.displayNameIsAuthorized(
ldapAuth.getAuthority())) {
return true;
}
}
} else {
for (SecurityRole secRole : securityRoles) {
if (secRole.displayNameIsAuthorized(
grantedAuth.getAuthority())) {
return true;
}
}
}
}
return false;
} catch (NullPointerException npe) {
logger.error("FIXME", npe);
return false;
}
}
private Collection<? extends GrantedAuthority> getGrantedAuthorities(
Authentication auth) {
if (auth == null) {
return Collections.emptyList();
}
try {
return auth.getAuthorities();
}
catch (Exception e) {
logger.error("Could not retrieve authorities", e);
return Collections.emptyList();
}
}
private Authentication getAuthentication() {
try {
SecurityContext secCtxt = SecurityContextHolder.getContext();
if (secCtxt == null) {
logger.warn("SecurityContextHolder.getContext() returned null, " +
+ "no authorities present");
return null;
}
Authentication auth = secCtxt.getAuthentication();
if (auth == null) {
logger.warn("SecurityContextHolder.getContext().getAuthentication() "
+ "returned null, no authorities present");
}
return auth;
} catch (Exception e) {
logger.error("Could not retrieve Authentication", e);
return null;
}
}
private void loadClassPropertyRoles() {
Map<Class<?>, Map<String, Collection<SecurityRole>>> newClassPropertyRoles =
new HashMap<>();
for (SecurityRoleToClassPropertyReader reader : securityRoleToClassPropertyReaders) {
Map<Class<?>, Map<String, Collection<SecurityRole>>> readerClassPropertyRoles =
reader.loadClassPropertyRoles();
for (Class<?> clazz : readerClassPropertyRoles.keySet()) {
Map<String, Collection<SecurityRole>> propertyRoles =
newClassPropertyRoles.get(clazz);
if (propertyRoles == null) {
propertyRoles = new HashMap<>();
newClassPropertyRoles.put(clazz, propertyRoles);
}
for (String propertyName : readerClassPropertyRoles.get(clazz).keySet()) {
Collection<SecurityRole> allowedRolesForProp =
propertyRoles.get(propertyName);
if (allowedRolesForProp == null) {
allowedRolesForProp = new ArrayList<>();
propertyRoles.put(propertyName, allowedRolesForProp);
}
Collection<SecurityRole> newLdapRoles =
readerClassPropertyRoles.get(clazz).get(propertyName);
for (SecurityRole securityRole : newLdapRoles) {
if (!allowedRolesForProp.contains(securityRole)) {
allowedRolesForProp.add(securityRole);
}
}
}
}
}
this.classPropertyRoles = newClassPropertyRoles;
}
}

Multiple select in thymeleaf + hibernate + spring boot

Hello guys I'm using thymeleaf 3 with spring boot and spring data jpa. But here is the problem. When I try to save I get this error from Hibernate:
Hibernate: insert into consulta (medico_id) values (?)
Hibernate: insert into consulta_pacientes (consulta_id, pacientes_id) values (?, ?)
2016-12-12 16:06:53.963 WARN 11912 --- [nio-9393-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1364, SQLState: HY000
2016-12-12 16:06:53.963 ERROR 11912 --- [nio-9393-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : Field 'pct_id' doesn't have a default value
2016-12-12 16:06:53.965 INFO 11912 --- [nio-9393-exec-9] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2016-12-12 16:06:53.976 ERROR 11912 --- [nio-9393-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibe
rnate.exception.GenericJDBCException: could not execute statement] with root cause
java.sql.SQLException: Field 'pct_id' doesn't have a default value
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:963) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526) ~[mysql-connector-java-5.1.39.jar:5.1.39]
I already tried to use converter but didn't workout properly. Tried to look in this posts* ...but didn't solve either.
*1 http://forum.thymeleaf.org/th-selected-not-working-on-lt-select-gt-lt-option-gt-td4029201.html
*2
thymeleaf multiple selected on edit
Any tips? I'm kind of lost right now.
cadastro.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
...
<form action="#" th:action="#{salvar}" th:object="${consulta}" method="POST">
<div class="form-inline">
<label for="select-medico-consulta" class="form-group">Medico</label>
<select th:field="*{medico.id}" id="select-medico-consulta" >
<div>
<option th:each="medicoEntry : ${medicos}"
th:value="${medicoEntry.id}"
th:text="${medicoEntry.nome}"></option>
</div>
</select>
<div class="form-group">
<label id="paciente-label" for="select-paciente" > Paciente</label>
<select th:field="*{pacientes}" id="select-paciente" size="5" multiple="multiple" >
<div>
<option th:each="pacienteEntry : ${listaPacientes}"
th:field="*{pacientes}"
th:value="${pacienteEntry.id}"
th:text="${pacienteEntry.nome}"></option>
</div>
</select>
</div>
</div>
<div class="form-group">
<label for="comment">Consulta</label>
<textarea class="form-control" rows="5" id="comment"></textarea>
</div>
<button type="submit" class="btn btn-default">Salvar</button>
</form>
</div>
...
consultaController.java
package
and imports...
#Controller
#RequestMapping("/medclin")
public class ConsultaController {
#Autowired
private ConsultaDao consultadao;
#Autowired
private MedicoDao medicoDao;
#Autowired
private PacienteDao pacienteDao;
#RequestMapping("/consulta")
public ModelAndView Consulta() {
ModelAndView modelAndView = new ModelAndView("consulta/consulta");
ArrayList<Medico> medicos = (ArrayList<Medico>) medicoDao.findAll();
ArrayList<Paciente> pacientes = (ArrayList<Paciente>) pacienteDao.findAll();
modelAndView.addObject("medicos", medicos);
modelAndView.addObject("listaPacientes", pacientes);
modelAndView.addObject("consulta", new Consulta());
return modelAndView;
}
#RequestMapping(value = "/salvar", method = RequestMethod.POST)
public String salvar(#ModelAttribute Consulta consulta) {
consultadao.save(consulta);
return "redirect:medclin/home";
}
}
consultaDao.java
package br.com.medclin.boot.daos;
import java.io.Serializable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import br.com.medclin.boot.models.Consulta;
#Repository
public interface ConsultaDao extends CrudRepository<Consulta , Integer>
{
}
EDIT:
as asked by #bphilipnyc
Paciente.java
#Entity
public class Paciente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String nome;
private Calendar dataNascimento;
private String endereco;
#NotNull
private String cpf;
#ManyToOne
private Plano planoDeSaude;
public Paciente(String nome, Calendar dataNascimento, String endereco, String cpf, Plano plano) {
super();
this.nome = nome;
this.dataNascimento = dataNascimento;
this.endereco = endereco;
this.cpf = cpf;
this.planoDeSaude = plano;
}
public Paciente(String nome, Calendar dataNascimento, String endereco, String cpf) {
super();
this.nome = nome;
this.dataNascimento = dataNascimento;
this.endereco = endereco;
this.cpf = cpf;
}
public Paciente(String pctCpf) {
this.cpf = pctCpf;
}
public Paciente() {
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Calendar getDataNascimento() {
return this.dataNascimento;
}
public void setDataNascimento(Calendar dataNascimento) {
this.dataNascimento = dataNascimento;
}
public String getEndereco() {
return this.endereco;
}
public void setEndereco(String endereco) {
this.endereco = endereco;
}
public String getCpf() {
return this.cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Plano getPlanoDeSaude() {
return planoDeSaude;
}
public void setPlanoDeSaude(Plano planoDeSaude) {
this.planoDeSaude = planoDeSaude;
}
public boolean equals(Paciente pct) {
if (this.id == pct.id)
return true;
else
return false;
}
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public String toString() {
return "Paciente [id=" + id + ", nome=" + nome + ", dataNascimento=" + dataNascimento + ", endereco=" + endereco
+ ", cpf=" + cpf + ", planoDeSaude=" + planoDeSaude + "]";
}
}
The problem was solved. It seems that if you change your hibernate mapping, you must recreate the database. I did that and the problem was solved.

Spring HashMap Form

I am creating an application with Spring Roo for generate documents. First of all the user create a document:
public class Document {
#NotNull
private String titleDocument;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisDateField")
private Set<DateField> dateFields = new HashSet<DateField>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisRadioButton")
private Set<RadioButtonField> radioButtonFields = new HashSet<RadioButtonField>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisStringField")
private Set<StringField> stringFields = new HashSet<StringField>();
}
There are 3 types of fields, for simplify, this is StringField (the others are almost the same):
public class StringField extends Field {
#NotNull
private String valueString;
#NotNull
private Boolean isEditable;
#ManyToOne
private Document relatedDocumentToThisStringField;
#NotNull
private String nameStringField;
}
When the document with fields is created, another user has to fill it. Since I dont know how much fields the document will have I need to create a HashMap Form (I am following this tutorial)
My HashMap is:
public class DynamicForm {
private Map<String, String> dynamicMap=new HashMap<String, String>();
public Map<String, String> getDynamicMap() {
return dynamicMap;
}
public void setDynamicMap(Map<String, String> dynamicMap) {
this.dynamicMap = dynamicMap;
}
}
In my FillDocumentController I have:
#RequestMapping(value = "/{id}", params = "form", produces = "text/html")
public String updateForm(#PathVariable("id") Long id, Model uiModel) {
...
// Create DynamicForm Map
DynamicForm dynamicForm = new DynamicForm();
for (Field field : allFields) {
// Is StringField?
if (field.getClass().equals(StringField.class) == true) {
StringField stringField = (StringField) field;
if( stringField.getIsEditable() == true ) {
dynamicForm.getDynamicMap().put(stringField.getNameStringField(), stringField.getValueString() );
}
}
}
uiModel.addAttribute("dynamicForm", dynamicForm);
return "filldocuments/update";
}
This is the view:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<form:form action="/DocumentGenerator/filldocuments/add" modelAttribute="dynamicForm" method="post">
<c:forEach items="${dynamicForm.dynamicMap}" var="element">
<input name="element['${element.key}']" value="${element.value}"/>
</c:forEach>
<input type="submit" value="Save" />
</form:form>
</div>
And this is the method that catch the modelAttribute:
#RequestMapping(value="/add", method = RequestMethod.POST, produces = "text/html")
public String update(#ModelAttribute(value="dynamicForm") DynamicForm dynamicForm, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
for( String key : dynamicForm.getDynamicMap().keySet() ) {
System.out.println("key="+key);
}
return "redirect:/filldocuments";
}
My problem is that dynamicForm is empty. There is another DynamicForm inside of uiModel and is empty too (I was in debug mode). Where is the data that the user fill?? I dont know what is wrong!!
My fault, the view has to be like that:
<c:forEach items="${dynamicForm.dynamicMap}" var="dynamicMap">
<input name="dynamicMap['${dynamicMap.key}']" value="${dynamicMap.value}"/>
</c:forEach>
So the error was use the variable element

Primefaces: setPropertyActionListener. Parameter gets null value

I have a dataGrid that iterates a list of object. In each grid I have a commandButton and a tag that tries to put the Id of the object selected in the backing bean, but when action is executed, and also in the setter method of the property, the value is null.
Here is my code:
<p:dataGrid var="element" value="#{CentroController.profiles}" columns="3"
rows="10" paginator="true" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" >
<p:panel header="#{CentroController.getDescripcionRoot(element)}" style="text-align:center">
<h:panelGrid columns="2" style="width:100%">
<p:panel>
<p:commandButton value="Borrar perfil" icon="ui-icon-trash" update=":form:tabView:profileButtonPanel" action="#{CentroController.deletePerfil}">
<f:setPropertyActionListener value="#{element.id}" target="#{CentroController.selectedItemId}" />
</p:commandButton>
</p:panel>
</h:panelGrid>
</p:panel>
</p:dataGrid>
In the backing bean:
public void deletePerfil()
{
System.out.println("SELECTED ITEM ID: " + this.selectedItemId);
// selectedItemID is always null
}
When setter is called, the value is also null:
public void setSelectedItemId(BigDecimal selectedItemId) {
System.out.println(selectedItemId); // Value is null
this.selectedItemId = selectedItemId;
}
Thanks.
Edit: the code of the bean (I removed irrelevant methods).
/* imports */
#Named("CentroController")
#SessionScoped
public class CentroController implements Serializable{
private #Inject CentrosDAO dao;
private #Inject CentrosCanalesDAO daoServicios;
private #Inject CatalogoCentrosLaboratorioDAO habitualLabDAO;
private #Inject CatalogoCentrosRadiologiaDAO habitualRadDAO;
private List<Centros> centros;
private Centros selectedCentro;
private List<CentrosCanales> selectedCanales=new ArrayList<CentrosCanales>();
private List<CentrosCanales> listado;
private CentrosCanales selected;
private CatalogoCentros selectedItem;
private BigDecimal selectedItemId;
private TreeNode root;
private DualListModel<Catalogo> listCatalogo;
private DualListModel <Catalogo> listCatalogoLabHabitual;
private DualListModel <Catalogo> listCatalogoRadHabitual;
private CatalogoCentros perfilNuevo=new CatalogoCentros();
private #Inject CentrosCanalesDAO consulta;
private #Inject CatalogoCentrosDAO consulta1;
private #Inject CatalogoDAO consulta2;
private boolean servicioIsSelected; //, perfilIsSelected, pruebaIsSelected;
private List<CatalogoCentros> profiles;
public CentroController() {
}
#PostConstruct
public void init(){
this.centros=dao.obtenListaCentros();
servicioIsSelected = false;
//perfilIsSelected = false;
}
public BigDecimal getSelectedItemId() {
return selectedItemId;
}
public void setSelectedItemId(BigDecimal selectedItemId) {
System.out.println(selectedItemId);
this.selectedItemId = selectedItemId;
}
public void deletePerfil()
{
System.out.println("SELECTED ITEM ID: " + this.selectedItemId);
}
}
UPDATED
The dataGrid is inside a rowExpansion tag within a datatable. I realized that if I put the dataGrid outside instead of nested in the datatable, it works. But I want it in the rowExpansion.
It only works If I put the datagrid outside of the tabView in which is included.
Some questions about CatalogoCentros:
Is the id field a BigDecimal?
Did you override the hashCode and equals?
If "no" to question 2, do something like this:
#Override
public int hashCode() {
return (id != null) ? id.intValue() : 0;
}
#Override
public boolean equals(final Object obj) {
if (obj instanceof CatalogoCentros) {
CatalogoCentros item = (CatalogoCentros) obj;
return item.getId().equals(getId());
}
return false;
}
Set a breakpoint in your equals method and see if that gets tripped when you select something in the dataGrid.

Form validation with spring mvc annotation

I got some trouble to get spring validation based on annotation form works.
i added this to my spring-servlet.xml
<context:component-scan base-package="com.it.controller" />
(package containing all my controller)
and
<context:component-scan base-package="com.it.form" />
(package containing all my form classes)
class email in package com.it.form :
public class email {
#NotEmpty
#Email
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public email() {
email = "";
// TODO Auto-generated constructor stub
}
}
Form :
<body>
<form:form method="post" action="" commandName='email'>
<div class="requestEmail">
<form:label path="email">Entrez votre email:</form:label>
<form:input path="email" />
<form:errors path="email" />
</div>
<div>
<input type="submit" value="VALIDER" />
</div>
</form:form>
Controller :
#Controller
#SessionAttributes
public class passwordController {
/*
* ##########################################################
*
* Print & valid form Email
*
* ##########################################################
*/
#RequestMapping(value = "/passwordChange.mvc", method = RequestMethod.GET)
public String get(final ModelMap model) {
email email= new email();
model.addAttribute("email", email);
return "passwordChangeRequestEmail"; // jsp form
}
#RequestMapping(value = "/passwordChange.mvc", method = RequestMethod.POST)
public String post(final ModelMap model,
#ModelAttribute("email") #Valid final email email,
final BindingResult result) {
if (result.hasErrors()) {
return "error";
}
return "success";
}
}
it seems when i submit my form i am always redirect to /success page, even if i leave email input blank...
Dunno if i missed something
Thanks in advance :)
You have to add
<mvc:annotation-driven />
to your servlet context file and to import a validator like Hibernate Validator in your classpath.

Resources