org.springframework.beans.factory.BeanCreationException using cdi - spring-security

I am trying to implement authentication and authorization using Spring Security Framework, but I am having a hard time, Im stuck in this exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clienteBO': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected br.com.logtec.dao.GenericCrudDAO br.com.logtec.business.GenericCrudBO.dao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crudDAO': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected javax.persistence.EntityManager br.com.logtec.dao.GenericCrudDAO.entityManager; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.persistence.EntityManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.inject.Inject(), #br.com.logtec.factory.DataFactory()}
Those are my related classes:
#Named("clienteBO")
public class ClienteBO extends PersonificacaoBO<Cliente>{
private static final long serialVersionUID = 119528316663693560L;
public ClienteBO() {
super();
}
#Override
public Feedback salvar(Cliente instancia) {
instancia.getPessoa().setCliente(true);
//TODO PEGAR EMPRESA DO USUARIO LOGADO
// if(instancia.getEmpresa() == null)
// throw new RuntimeException("O cliente deve obrigatoriamente possuir uma empresa");
return super.salvar(instancia);
}
#Override
public Feedback salvar(Cliente instancia, CrudDAO<Cliente> dao) {
instancia.getPessoa().setCliente(true);
return super.salvar(instancia, dao);
}
#Override
protected Exemplo criarExemplo(Cliente pesquisa) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return super.criarExemplo(pesquisa);
}
#Override
public Feedback salvar(Collection<Cliente> instancias) {
for (Cliente cliente : instancias) {
cliente.getPessoa().setCliente(true);
}
return super.salvar(instancias);
}
#Override
public Feedback salvar(Collection<Cliente> instancias, CrudDAO<Cliente> dao) {
for (Cliente cliente : instancias) {
cliente.getPessoa().setCliente(true);
}
return super.salvar(instancias, dao);
}
}
public abstract class PersonificacaoBO<T extends Personificacao> extends GenericCrudBO<T>{
private static final long serialVersionUID = 5475960092794378740L;
#Override
protected Exemplo criarExemplo(T pesquisa) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Exemplo exemplo = super.criarExemplo(pesquisa);
exemplo.excludeField("pessoa.cliente");
exemplo.excludeField("pessoa.funcionario");
exemplo.excludeField("pessoa.fornecedor");
exemplo.excludeField("pessoa.usuario");
exemplo.excludeField("pessoa.contador");
return exemplo;
}
}
#Named("crudBO")
public class GenericCrudBO<E extends EntidadeBase> implements CrudBO<E>{
private static final long serialVersionUID = 1L;
private static final String DEFAULT_ERROR_MESSAGE = "Um erro inesperado ocorreu, contate o administrador do sistema.";
private static final String DEFAULT_SUCESS_MESSAGE = "Operação realizada com sucesso!";
#Inject
#Named("crudDAO")
protected GenericCrudDAO<E> dao;
public GenericCrudBO() {
super();
}
public GenericCrudBO(GenericCrudDAO<E> dao) {
super();
this.dao = dao;
}
public Feedback salvar(E instancia, CrudDAO<E> dao) {
Feedback feedback;
try {
dao.atualizar(instancia);
feedback = new Feedback(TipoFeedback.SUCESSO, EtapaFeedback.CADASTRO, DEFAULT_SUCESS_MESSAGE);
} catch (RuntimeException e) {
feedback = new Feedback(TipoFeedback.ERRO, EtapaFeedback.CADASTRO, DEFAULT_ERROR_MESSAGE);
throw e;
}
return feedback;
}
public Feedback salvar(Collection<E> instancias, CrudDAO<E> dao) {
try {
dao.cadastrar(instancias);
return new Feedback(TipoFeedback.SUCESSO, EtapaFeedback.CADASTRO, "Operação realizada com sucesso");
} catch (Exception e) {
return new Feedback(TipoFeedback.ERRO, EtapaFeedback.CADASTRO, "Erro ao salvar, contate o administrador");
}
}
#Override
public Feedback salvar(Collection<E> instancias) {
return salvar(instancias, dao);
}
public Feedback salvar(E instancia) {
return salvar(instancia, dao);
}
#Override
public Feedback deletar(E entidade) {
Feedback feedback;
try {
dao.deletar(entidade);
feedback = new Feedback(TipoFeedback.SUCESSO, EtapaFeedback.CADASTRO, DEFAULT_SUCESS_MESSAGE);
} catch (RuntimeException e) {
feedback = new Feedback(TipoFeedback.ERRO, EtapaFeedback.DELECAO, DEFAULT_ERROR_MESSAGE);
}
return feedback;
}
public E pesquisarPorId(Class<E> clazz, Long id) {
return dao.pesquisarPorId(clazz, id);
}
public E pesquisarPorId(E instancia) {
return dao.pesquisarPorId(instancia);
}
public List<E> pesquisar(Class<E> clazz) {
return dao.pesquisarTodos(clazz);
}
/**
* Pesquisa para entidades simples sem composição
*/
#Override
public List<E> pesquisar(E pesquisa) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Exemplo exemplo = criarExemplo(pesquisa);
return dao.pesquisar(exemplo);
}
protected Exemplo criarExemplo(E pesquisa) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Exemplo exemplo = new Exemplo(pesquisa);
exemplo.excludeField("serialVersionUID");
exemplo.setMatchingMode(MatchingMode.ANYWHERE);
exemplo.excludeZeroes();
return exemplo;
}
#Override
public int total(E pesquisa) {
return this.dao.total(pesquisa);
}
public List<E> listarLazy(E pesquisa, int startingAt, int maxPerPage, String sortField, String sortOrder) {
inicializarCamposPesquisa(pesquisa);
return this.dao.listarLazy(pesquisa, startingAt, maxPerPage, sortField, sortOrder);
}
protected void inicializarCamposPesquisa(E pesquisa) {
//método que deverá ser implementado pelas classes filhas que quiserem filtrar os resultados no lazyList
}
public String getListIds(List<EntidadeBase> entidades) {
StringBuilder builder = new StringBuilder('(');
EntidadeBase e = null;
for (int i = 0; i < entidades.size(); i++) {
e = entidades.get(i);
builder.append(e.getId());
if(i < entidades.size()-1) {
builder.append(',');
}
}
builder.append(')');
return builder.toString();
}
#SuppressWarnings("unchecked")
protected Class<E> getClassType() {
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
return (Class<E>) parameterizedType.getActualTypeArguments()[0];
}
}
#Named("crudDAO")
public class GenericCrudDAO<E extends EntidadeBase> implements CrudDAO<E>{
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CrudDAO.class);
#Inject
#DataFactory
protected EntityManager entityManager;
public GenericCrudDAO() {
super();
}
public GenericCrudDAO(EntityManager entityManager) {
super();
this.entityManager = entityManager;
}
#Override
public void cadastrar(E instancia) {
entityManager.getTransaction().begin();
entityManager.persist(instancia);
entityManager.getTransaction().commit();
}
public void cadastrar(Collection<E> instancias) {
try {
entityManager.getTransaction().begin();
for(E e : instancias) {
entityManager.merge(e);
}
entityManager.getTransaction().commit();
} catch (Exception e) {
entityManager.getTransaction().rollback();
throw e;
}
}
#Override
public void atualizar(E instancia) {
entityManager.getTransaction().begin();
entityManager.merge(instancia);
entityManager.getTransaction().commit();
}
#Override
public void deletar(E instancia) {
entityManager.getTransaction().begin();
entityManager.remove(entityManager.merge(instancia));
entityManager.getTransaction().commit();
}
public E pesquisarPorId(Class<E> clazz, Long id) {
return (E) entityManager.find(clazz, id);
}
#SuppressWarnings("unchecked")
public E pesquisarPorId(E instancia) {
Class<E> clazz = (Class<E>) instancia.getClass();
return (E) entityManager.find(clazz, instancia.getId());
}
#SuppressWarnings("unchecked")
public List<E> pesquisarTodos(Class<E> clazz) {
List<E> lista = new ArrayList<E>();
lista = entityManager.createQuery(" FROM " + clazz.getName()).getResultList();
return lista;
}
#Override
public List<E> pesquisar(Exemplo exemplo) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return QBE.using(entityManager).getList(exemplo);
}
#Override
public E pesquisarUnico(Exemplo exemplo) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return QBE.using(entityManager).getSingle(exemplo);
}
#Override
#SuppressWarnings("unchecked")
public List<E> pesquisar(String queryString) {
return entityManager.createQuery(queryString).getResultList();
}
#SuppressWarnings("unchecked")
#Override
public List<E> pesquisar(String queryString, Map<String, Object> param) {
String key = null;
Query query = entityManager.createQuery(queryString);
for(Map.Entry<String, Object> entry : param.entrySet()) {
key = entry.getKey().trim();
key = key.startsWith(":") ? key.substring(1) : key;
query.setParameter(key, entry.getValue());
}
return query.getResultList();
}
public int total(E pesquisa) {
Long count = 0L;
try {;
Query q = entityManager.createQuery("SELECT count(*) FROM "
+ pesquisa.getClass().getName());
count = (Long) q.getSingleResult();
} catch (Exception e) {
LOGGER.error("Erro ao buscar total listagem lazy", e);
}
return count.intValue();
}
public void rollback() {
entityManager.getTransaction().rollback();
}
#SuppressWarnings("unchecked")
protected Class<E> getClassType() {
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
return (Class<E>) parameterizedType.getActualTypeArguments()[0];
}
#SuppressWarnings("unchecked")
public List<E> listarLazy(E pesquisa, int startingAt, int maxPerPage,
String sortField, String sortOrder) {
List<E> lista = new ArrayList<E>();
try {
Query q = entityManager.createQuery("FROM "
+ pesquisa.getClass().getName());
q.setFirstResult(startingAt);
q.setMaxResults(maxPerPage);
lista = q.getResultList();
} catch (Exception e) {
LOGGER.error("Erro ao buscar listagem Lazy", e);
}
return lista;
}
}
I'm a begginer on Spring Security, being so, any help is welcome, thanks

If I get this right, you want to use Spring Security for security and CDI for dependency injection.
In that case, you need to make sure that Spring and CDI don't try to manage the same beans. Even when you don't use Spring Core directly, you now have both Spring and CDI on your classpath. When Spring discovers javax.inject.Inject on its classpath, it will treat #Inject as synonymous to #Autowired and try to inject Spring beans into the annotated injection target.
That's why you get the exception - it's Spring and not CDI complaining about a missing bean.

Related

How to use Filter in Spring Cloud Data Flow?

I would like to add a Filter in Spring Cloud Data Flow (SCDF) to debug and see how it works when receiving some requests.
I have tried to implements javax.servlet.Filter and override doFilter method but It's seem not work because there are some default Filter of SCDF had been started before my Filter class.
Are there any way do write a filter for SCDF? Is it possible if I apply this link for this purpose?
This is my Filter class:
#Component
public class CustomFilter implements Filter {
#Override
public void destroy() {
System.out.println("init fillter ");
}
#Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
try {
HttpServletRequest req = (HttpServletRequest) arg0;
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(
(HttpServletResponse) arg1);
ResettableStreamHttpServletRequest wrappedRequest = new ResettableStreamHttpServletRequest(
(HttpServletRequest) req);
logger.info(">>>>>link: " + req.getServletPath() + "?");
for (Entry<String, String[]> entry : req.getParameterMap().entrySet()) {
logger.info(">>>>>param: " + entry.getKey() + ":" + entry.getValue()[0]);
}
String bodyRequest = IOUtils.toString(wrappedRequest.getReader());
logger.info(">>>>>link: " + req.getServletPath() + "?");
for (Entry<String, String[]> entry : req.getParameterMap().entrySet()) {
logger.info(">>>>>param: " + entry.getKey() + ":" + entry.getValue()[0]);
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", 2);
javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
try {
logger.info("Request: " + bodyRequest);
} catch (Exception e) {
logger.info("Request: " + bodyRequest);
}
wrappedRequest.resetInputStream();
arg2.doFilter(wrappedRequest, responseWrapper);
logger.info("Response: " + IOUtils.toString(responseWrapper.getContentInputStream()));
responseWrapper.copyBodyToResponse();
} catch (Exception ex) {
logger.info("doFilter: " + ex);
}
}
#Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("init fillter " + arg0);
}
private static class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper {
private byte[] rawData;
private HttpServletRequest request;
private ResettableServletInputStream servletStream;
public ResettableStreamHttpServletRequest(HttpServletRequest request) {
super(request);
this.request = request;
this.servletStream = new ResettableServletInputStream();
}
public void resetInputStream() {
servletStream.stream = new ByteArrayInputStream(rawData);
}
#Override
public ServletInputStream getInputStream() throws IOException {
if (rawData == null) {
rawData = IOUtils.toByteArray(this.request.getReader());
servletStream.stream = new ByteArrayInputStream(rawData);
}
return servletStream;
}
#Override
public BufferedReader getReader() throws IOException {
if (rawData == null) {
rawData = IOUtils.toByteArray(this.request.getReader());
servletStream.stream = new ByteArrayInputStream(rawData);
}
return new BufferedReader(new InputStreamReader(servletStream));
}
private class ResettableServletInputStream extends ServletInputStream {
private InputStream stream;
#Override
public int read() throws IOException {
return stream.read();
}
#Override
public boolean isFinished() {
return false;
}
#Override
public boolean isReady() {
return false;
}
#Override
public void setReadListener(ReadListener arg0) {
}
}
}
}
Spring Cloud Data Flow server is inherently a Spring Boot application and hence it allows you to inject specific configuration beans into Data Flow configuration to extend/customize.
In your case, you can create a bean that extends javax.servlet.http.HttpFilter or implements javax.servlet.Filter and have that bean injected into SCDF configuration.

java.lang.NoSuchMethodError using JDBI

public class MyApplication extends Application<MyConfiguration> {
final static Logger LOG = Logger.getLogger(MyApplication.class);
public static void main(final String[] args) throws Exception {
new MyApplication().run(args);
}
#Override
public String getName() {
return "PFed";
}
#Override
public void initialize(final Bootstrap<MyConfiguration> bootstrap) {
// TODO: application initialization
bootstrap.addBundle(new DBIExceptionsBundle());
}
#Override
public void run(final MyConfiguration configuration,
final Environment environment) {
// TODO: implement application
final DBIFactory factory = new DBIFactory();
final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "postgresql");
UserDAO userDAO = jdbi.onDemand(UserDAO.class);
userDAO.findNameById(1);
UserResource userResource = new UserResource(new UserService(userDAO));
environment.jersey().register(userResource);
}
I get the the following error at findNameById.
java.lang.NoSuchMethodError: java.lang.Object.findNameById(I)Ljava/lang/String;
at org.skife.jdbi.v2.sqlobject.CloseInternalDoNotUseThisClass$$EnhancerByCGLIB$$a0e63670.CGLIB$findNameById$5()
}
public interface UserDAO {
#SqlQuery("select userId from user where id = :email")
User isEmailAndUsernameUnique(#Bind("email") String email);
#SqlQuery("select name from something where id = :id")
String findNameById(#Bind("id") int id);
}

Default to content_type application/json with overriden isFatal from DefaultExceptionStrategy

I'd like to not require my clients to provide content_type application/json but just default to it. I got this working.
I also tried to combine with another example to implement a custom isFatal(Throwable t) from ConditionalRejectingErrorHandler. I can get my custom error handler to fire, but then it seems to require the content_type property again. I can't figure out how to get them both to work at the same time.
Any ideas?
The below successfully works to not require content_type
EDIT: The below code does not work as I thought. An old message in the queue with the property content_type application/json must have been pulled in
#EnableRabbit
#Configuration
public class ExampleRabbitConfigurer implements
RabbitListenerConfigurer {
#Value("${spring.rabbitmq.host:'localhost'}")
private String host;
#Value("${spring.rabbitmq.port:5672}")
private int port;
#Value("${spring.rabbitmq.username}")
private String username;
#Value("${spring.rabbitmq.password}")
private String password;
#Autowired
private MappingJackson2MessageConverter mappingJackson2MessageConverter;
#Autowired
private DefaultMessageHandlerMethodFactory messageHandlerMethodFactory;
#Bean
public MappingJackson2MessageConverter mappingJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(mappingJackson2MessageConverter);
return factory;
}
#Override
public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
}
The below here works to override isFatal() in ConditionalRejectingErrorHandler. The SimpleRabbitListenerContainerFactory.setMessageConverter() seems like it should serve the same purpose as DefaultMessageHandlerMethodFactory.setMessageConverter(). Obviously this is not the case.
#EnableRabbit
#Configuration
public class ExampleRabbitConfigurer {
#Value("${spring.rabbitmq.host:'localhost'}")
private String host;
#Value("${spring.rabbitmq.port:5672}")
private int port;
#Value("${spring.rabbitmq.username}")
private String username;
#Value("${spring.rabbitmq.password}")
private String password;
#Autowired
ConnectionFactory connectionFactory;
#Autowired
Jackson2JsonMessageConverter jackson2JsonConverter;
#Autowired
ErrorHandler amqpErrorHandlingExceptionStrategy;
#Bean
public Jackson2JsonMessageConverter jackson2JsonConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public ErrorHandler amqpErrorHandlingExceptionStrategy() {
return new ConditionalRejectingErrorHandler(new AmqpErrorHandlingExceptionStrategy());
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(jackson2JsonConverter);
factory.setErrorHandler(amqpErrorHandlingExceptionStrategy);
return factory;
}
public static class AmqpErrorHandlingExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy {
private final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(getClass());
#Override
public boolean isFatal(Throwable t) {
if (t instanceof ListenerExecutionFailedException) {
ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t;
LOGGER.error("Failed to process inbound message from queue "
+ lefe.getFailedMessage().getMessageProperties().getConsumerQueue()
+ "; failed message: " + lefe.getFailedMessage(), t);
}
return super.isFatal(t);
}
}
Use an "after receive" MessagePostProcessor to add the contentType header to the inbound message.
Starting with version 2.0, you can add the MPP to the container factory.
For earlier versions you can reconfigure...
#SpringBootApplication
public class So47424449Application {
public static void main(String[] args) {
SpringApplication.run(So47424449Application.class, args);
}
#Bean
public ApplicationRunner runner(RabbitListenerEndpointRegistry registry, RabbitTemplate template) {
return args -> {
SimpleMessageListenerContainer container =
(SimpleMessageListenerContainer) registry.getListenerContainer("myListener");
container.setAfterReceivePostProcessors(m -> {
m.getMessageProperties().setContentType("application/json");
return m;
});
container.start();
// send a message with no content type
template.setMessageConverter(new SimpleMessageConverter());
template.convertAndSend("foo", "{\"bar\":\"baz\"}", m -> {
m.getMessageProperties().setContentType(null);
return m;
});
template.convertAndSend("foo", "{\"bar\":\"qux\"}", m -> {
m.getMessageProperties().setContentType(null);
return m;
});
};
}
#Bean
public Jackson2JsonMessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
#RabbitListener(id = "myListener", queues = "foo", autoStartup = "false")
public void listen(Foo foo) {
System.out.println(foo);
if (foo.bar.equals("qux")) {
throw new MessageConversionException("test");
}
}
public static class Foo {
public String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return "Foo [bar=" + this.bar + "]";
}
}
}
As you can see, since it modifies the source message, the modified header is available in the error handler...
2017-11-22 09:39:26.615 WARN 97368 --- [cTaskExecutor-1] ingErrorHandler$DefaultExceptionStrategy : Fatal message conversion error; message rejected; it will be dropped or routed to a dead letter exchange, if so configured: (Body:'{"bar":"qux"}' MessageProperties [headers={}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=foo, deliveryTag=2, consumerTag=amq.ctag-re1kcxKV14L_nl186stM0w, consumerQueue=foo]), contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=foo, deliveryTag=2, consumerTag=amq.ctag-re1kcxKV14L_nl186stM0w, consumerQueue=foo])

p:selectOneMenu not calling setter on form submit

I'm kinda new to JSF and primefaces and I'm running into a very annoying problem.
I'm making a very basic application to learn a bit more about primefaces. I have a simple form that has several textual input fields, two datepickers and one dropdown (selectOneMenu).
Everything works all values are put in the backing bean when I submit the form, except for the value from the dropdown menu. The setter for that item is never called. And the application does not call the public void saveNewActivity(ActionEvent evt) method on the controller as defined on the commandbutton. When I however remove or comment out the dropdown menu in html it does call that method (but the field for the dropdown menu is obviously null).
I've been trying things for nearly two days, and still can't get this to work properly.
I have the following code (snippets):
My html/jsf code
<div id="newActivitycontent">
<h:form id="newActivityForm">
<h:messages id="messages"/>
<table>
<tr>
<td>Gebruiker:</td>
<td><p:selectOneMenu value="#{plannedActivityController.newActivity.organiser}}"
converter="#{userConverter}">
<f:selectItem itemLabel="Kies een gebruiker" itemValue=""/>
<f:selectItems value="#{plannedActivityController.users}" var="user"
itemLabel="#{user.firstname} #{user.lastname}" itemValue="#{user}"/>
</p:selectOneMenu></td>
</tr>
<tr>
<td>Titel:</td>
<td><p:inputText value="#{plannedActivityController.newActivity.name}"/></td>
</tr>
<tr>
<td>Beschrijving:</td>
<td><p:inputText value="#{plannedActivityController.newActivity.desctription}"/></td>
</tr>
<tr>
<td>Startdatum:</td>
<td><p:calendar value="#{plannedActivityController.newActivity.startDateDate}"/></td>
</tr>
<tr>
<td>Einddatum:</td>
<td><p:calendar value="#{plannedActivityController.newActivity.endDateDate}"/></td>
</tr>
</table>
<p:commandButton id="btnSaveNewActivity" value="Opslaan"
actionListener="#{plannedActivityController.saveNewActivity}"
update=":overviewForm:activityTable messages"/>
<p:commandButton id="btnCancelNewActivity" value="Annuleren"
actionListener="#{plannedActivityController.cancelNewActivity}" onclick="hideAddNewUI()"
update=":overviewForm:activityTable" type="reset" immediate="true"/>
</h:form>
</div>
The controller that is used by that code:
#Named
#SessionScoped
public class PlannedActivityController implements Serializable {
#Inject
private ApplicationModel appModel;
#Inject
private SessionModel sessionModel;
#Inject
private ActivityMapper activityMapper;
#Inject
private UserMapper userMapper;
private ActivityBean newActivity;
private ActivityBean selectedActivity;
private List<ActivityBean> activities;
private List<UserBean> users;
public PlannedActivityController() {
}
#PostConstruct
public void onCreated() {
convertActivities();
onNewActivity();
users = userMapper.mapToValueObjects(appModel.getUsers());
}
public void convertActivities() {
List<PlannedActivity> originalActivities = appModel.getActivities();
this.activities = activityMapper.mapToValueObjects(originalActivities);
}
public void onRowEditComplete(RowEditEvent event) {
System.out.println("row edited : " + event.getObject());
//TODO: save changes back to db!
}
public void onRowSelectionMade(SelectEvent event) {
System.out.println("row selected : " + event.getObject());
selectedActivity = (ActivityBean)event.getObject();
}
//Activity crud methods
public void onNewActivity() {
newActivity = new ActivityBean();
newActivity.setId(new Date().getTime());
}
public void saveNewActivity(ActionEvent evt) {
PlannedActivity newAct = activityMapper.mapToEntity(newActivity);
if(newAct != null) {
appModel.getActivities().add(newAct);
}
convertActivities();
}
public void cancelNewActivity() {
//TODO: cleanup.
}
public void deleteSelectedActivity() {
if(selectedActivity != null) {
activities.remove(selectedActivity);
appModel.setActivities(activityMapper.mapToEntities(activities));
convertActivities();
} else {
//TODO: show error or information dialog, that delete cannot be done when nothing has been selected!
}
}
//Getters & Setters
public ApplicationModel getAppModel() {
return appModel;
}
public void setAppModel(ApplicationModel appModel) {
this.appModel = appModel;
}
public SessionModel getSessionModel() {
return sessionModel;
}
public void setSessionModel(SessionModel sessionModel) {
this.sessionModel = sessionModel;
}
public ActivityMapper getActivityMapper() {
return activityMapper;
}
public void setActivityMapper(ActivityMapper activityMapper) {
this.activityMapper = activityMapper;
}
public UserMapper getUserMapper() {
return userMapper;
}
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public ActivityBean getNewActivity() {
return newActivity;
}
public void setNewActivity(ActivityBean newActivity) {
this.newActivity = newActivity;
}
public ActivityBean getSelectedActivity() {
return selectedActivity;
}
public void setSelectedActivity(ActivityBean selectedActivity) {
this.selectedActivity = selectedActivity;
}
public List<ActivityBean> getActivities() {
return activities;
}
public void setActivities(List<ActivityBean> activities) {
this.activities = activities;
}
public List<UserBean> getUsers() {
return users;
}
public void setUsers(List<UserBean> users) {
this.users = users;
}
}
My activitybean:
public class ActivityBean implements Serializable {
private Long id = 0L;
private String name;
private String desctription;
private UserBean organiser;
private Calendar startDate;
private Calendar endDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesctription() {
return desctription;
}
public void setDesctription(String desctription) {
this.desctription = desctription;
}
public UserBean getOrganiser() {
return organiser;
}
public void setOrganiser(UserBean organiser) {
this.organiser = organiser;
}
public Calendar getStartDate() {
return startDate;
}
public void setStartDate(Calendar startDate) {
this.startDate = startDate;
}
public Date getStartDateDate() {
if(this.startDate == null) {
return null;
}
return this.endDate.getTime();
}
public void setStartDateDate(Date startDate) {
if(this.startDate == null) {
this.startDate = new GregorianCalendar();
}
this.startDate.setTime(startDate);
}
public String getStartDateString() {
if(this.startDate == null) {
return null;
}
return startDate.get(Calendar.DAY_OF_MONTH) + "/" + startDate.get(Calendar.MONTH) + "/" + startDate.get(Calendar.YEAR) + "";
}
public Calendar getEndDate() {
return endDate;
}
public void setEndDate(Calendar endDate) {
this.endDate = endDate;
}
public Date getEndDateDate() {
if(this.endDate == null) {
return null;
}
return endDate.getTime();
}
public void setEndDateDate(Date endDate) {
if(this.endDate == null) {
this.endDate = new GregorianCalendar();
}
this.endDate.setTime(endDate);
}
public String getEndDateString() {
if(this.endDate == null) {
return null;
}
return endDate.get(Calendar.DAY_OF_MONTH) + "/" + endDate.get(Calendar.MONTH) + "/" + endDate.get(Calendar.YEAR) + "";
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ActivityBean that = (ActivityBean) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
My userbean:
public class UserBean {
private Long id;
private String username;
private String firstname;
private String lastname;
private String email;
private String phone;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserBean userBean = (UserBean) o;
if (id != null ? !id.equals(userBean.id) : userBean.id != null) return false;
return true;
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
And the converter used by the selectOneMenu:
#Named
public class userConverter implements Converter{
#Inject
private PlannedActivityController activityController;
#Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
for (UserBean user : activityController.getUsers()) {
if(user.getId().toString().equals(s)) {
return user;
}
}
return null;
}
#Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
if(o instanceof UserBean) {
UserBean user = (UserBean)o;
return user.getId().toString();
}
return "";
}
}
The problem is here. Look closer. This is invalid EL syntax.
value="#{plannedActivityController.newActivity.organiser}}"
This should however have thrown a PropertyNotWritableException on submit something like this:
javax.el.PropertyNotWritableException: /test.xhtml #25,39 value="#{plannedActivityController.newActivity.organiser}}": Illegal Syntax for Set Operation
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:136)
at javax.faces.component.UIInput.updateModel(UIInput.java:822)
at javax.faces.component.UIInput.processUpdates(UIInput.java:739)
at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1244)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1244)
at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1223)
at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
This exception should have been logged to the server log. By default this will however not end up in an error page for the enduser because JSF/PrimeFaces have by default no form of feedback to enduser in case of exceptions which are thrown during ajax requests. You should however be able to see it in actual ajax response body in webbrowser's builtin HTTP traffic monitor.
The JSF utility library OmniFaces offers a FullAjaxExceptionHandler for the very problem of total absence of feedback on exceptions during ajax requests. You may find it useful. When I tried to recreate your problem, I was been presented a clear error page so that I don't need to dig in server log or HTTP traffic monitor for clues.

How to get parent of a custom component?

I have a custom container component, that I want to use like this:
<p:a>A
<p:a>B</p:a>
</p:a>
That should generate this markup:
<div>A
<div>B</div>
</div>
Code for the component is below.
public class TagA extends TagHandler {
Logger logger = Logger.getLogger(getClass().getName());
public TagA(TagConfig config) {
super(config);
}
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException {
UIComponentBase c = new UIComponentBase() {
public void encodeBegin(FacesContext ctx) throws IOException {
//getParent() always returns UIViewRot
logger.info("Parent is: " + getParent().getClass().getName());
ResponseWriter w = ctx.getResponseWriter();
w.write("<div>");
super.encodeBegin(ctx);
}
public void encodeEnd(FacesContext ctx) throws IOException {
ResponseWriter w = ctx.getResponseWriter();
w.write("</div>");
super.encodeEnd(ctx);
}
// abstract method in base, must override
public String getFamily() {
return "com.mobiarch.nf";
}
};
parent.getChildren().add(c);
nextHandler.apply(ctx, parent);
}
}
Unfortunately, this is rendering the following markup:
<div></div>A
<div></div>B
For others in a similar situation, just develop the component and not the tag.
#FacesComponent("my.ComponentA")
public class ComponentA extends UIComponentBase {
Logger logger = Logger.getLogger(getClass().getName());
public String getFamily() {
return "my.custom.component";
}
public void encodeBegin(FacesContext ctx) throws IOException {
super.encodeBegin(ctx);
logger.info("Component parent is: " + getParent().getClass().getName());
ResponseWriter w = ctx.getResponseWriter();
w.write("<div>");
}
public void encodeEnd(FacesContext ctx) throws IOException {
super.encodeEnd(ctx);
ResponseWriter w = ctx.getResponseWriter();
w.write("</div>");
}
}
Register it in your ??.taglib.xml
<tag>
<tag-name>a</tag-name>
<component>
<component-type>my.ComponentA</component-type>
</component>
</tag>

Resources