Hibernate EmptyInterceptor onFlushDirty() is not executing - java

I want to do Audit for my entity updates. So I have implemented EmptyInterceptor.
My onFlushDirty() method is not executing, but afterTransactionCompletion() does executes
I'm using Spring 4.1 and Hibernate 5.0
+
I have not done any configuration rather than #Component in configuration file till afterTransactionCompletion() get executed.
What I'm missing here ?
Also how to intercept Event query.executeUpdate() ?
My Interceptor class is as follows:
#Component
public class AuditLogInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 1L;
#Override
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
System.out.println("AuditLogInterceptor.onFlushDirty()");
System.out.println();
System.out.println("Property Names :- ");
for (String propertyName : propertyNames) {
System.out.print(", "+propertyName);
}
System.out.println();
System.out.println("Current State :- ");
for (Object current : currentState) {
System.out.print(", "+ String.valueOf( current ) );
}
System.out.println();
System.out.println("Previous State :- ");
for (Object previous : previousState) {
System.out.print(", "+ String.valueOf( previous ) );
}
return true;
//return super.onFlushDirty(entity, id, currentState, previousState,
//propertyNames, types);
}
#Override
public void afterTransactionCompletion(Transaction tx) {
// TODO Auto-generated method stub
System.out.println("AuditLogInterceptor.afterTransactionCompletion()");
super.afterTransactionCompletion(tx);
}
#Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
System.out.println("AuditLogInterceptor.onSave()");
System.out.println("Property Names :- "+Arrays.toString(propertyNames));
System.out.println("States :- "+Arrays.toString(state));
return super.onSave(entity, id, state, propertyNames, types);
}
#Override
public void postFlush(#SuppressWarnings("rawtypes") Iterator entities) {
System.out.println();
System.out.println("AuditLogInterceptor.postFlush()");
for ( ; entities.hasNext() ;) {
System.out.println("-----"+ entities.next().getClass().getSimpleName());
}
System.out.println();
super.postFlush(entities);
}
}
Code In my DAO
#Override
public boolean updateAssignment( Integer workTaskDetailId, short workTaskStatus ) {
Session session = null;
Transaction transaction = null;
boolean isUpdated = false;
try {
session = this.sessionFactory.withOptions().interceptor( new AuditLogInterceptor() ).openSession();
transaction = session.beginTransaction();
String COMPLETION_DATE = "";
if( workTaskStatus == 263 )
COMPLETION_DATE = ", wtd.completionDate = :completionDate ";
final String UPDATE_WORKTASKSTATUS = "update WorkTaskDetail wtd set wtd.workTaskStatus = :workTaskStatus "
+COMPLETION_DATE+ "where wtd.workTaskDetailId = :workTaskDetailId ";
Query query = session.createQuery(UPDATE_WORKTASKSTATUS).setShort("workTaskStatus", workTaskStatus)
.setInteger("workTaskDetailId", workTaskDetailId);
if( workTaskStatus == 263 )
query.setDate("completionDate", new Date() );
int updateCount = query.executeUpdate();
if( updateCount > 0 )
isUpdated = true;
if( session != null )
session.flush();
if( transaction != null && transaction.getStatus().equals(TransactionStatus.ACTIVE) )
transaction.commit();
} catch ( Exception exception ) {
if( transaction != null && transaction.getStatus().equals( TransactionStatus.ACTIVE) )
transaction.rollback();
LOGGER.error("Message :- "+exception.getMessage());
LOGGER.error("Root Cause :- "+exception.getCause());
LOGGER.error(" ************************************************************");
} finally {
if( session != null )
session.close();
}
return isUpdated;
}

The onFlushDirty method was not called because there was no entity being modified by the currently running Persistence Context.
Only managed entities can generate automatic UPDATE statements. In your case, you are executing a manual SQL UPDATE, which is beyond the scope of Hibernate entity state transitions.
Therefore, you have two choices:
Use Hibernate Envers as there is no need to write a homemade Audit Log on top of Hibernate.
Use Debezium since the DB already features an Audit Log anyway (a.k.a. WAL, redo log, transaction log).

Related

what is this following error about in spring rest webservice api?

I'am creating a restapi , i am using java spring and i'am getting the following error.
Error:
org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
My daoImpl class
#Override
public String getLoginDetails(VendorLogin vendorlogin) {
String getVendorData = "select vendor_ID from vendor_login where vendor_ID= ?
and password=?";
String name =null;
try{
name = (String) jdbcTemplate.queryForObject(getVendorData,new Object[]{
vendorlogin.getVendorLoginId(), vendorlogin.getPassWord()}, String.class);
}catch(Exception e){
e.printStackTrace();
}
return name;
}
my controller
#RequestMapping(value = Constants.REQ_MAP_LOGIN,
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
public String vendorloginMethodPost(#RequestBody VendorLogin vendoridlogin) {
String message = Constants.EMPTY_STRING;
String id = dao.getLoginDetails(vendoridlogin);
String password = dao.getLoginDetails(vendoridlogin);
if (id == null && password==null) {
message = "login FAIL";
}else{
message =" login Successfully";
}
return message;
}
SOLUTION
#Override
public String getLoginDetails(VendorLogin vendorlogin) {
String getVendorData = "select vendor_ID from vendor_login where vendor_ID= ? and password=?";
try {
name = (String) jdbcTemplate.queryForObject(
getVendorData,
new Object[]{vendorlogin.getVendorLoginId(), vendorlogin.getPassWord()},
new RowMapper<YourVendorObject>() {
public UserAttempts mapRow(ResultSet rs, int rowNum) throws SQLException {
// we suppose that your vendor_ID is String in DB
String vendor_ID = rs.getString("vendor_ID");
// if you wanna return the whole object use setters and getters
// from rs.getInt ... rs.getString ...
return vendor_ID;
}
});
return name;
} catch (EmptyResultDataAccessException e) {
return null;
}
}
public class EmptyResultDataAccessException extends IncorrectResultSizeDataAccessException
Data access exception thrown when a result was expected to have at least one row (or element) but zero rows (or elements) were actually returned.
The problem is, Spring throws an EmptyResultDataAccessException, instead of returning a null when record not found :
JdbcTemplate .java
package org.springframework.jdbc.core;
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
//...
public <T> T queryForObject(String sql, Object[] args,
RowMapper<T> rowMapper) throws DataAccessException {
List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
return DataAccessUtils.requiredSingleResult(results);
}
DataAccessUtils.java
package org.springframework.dao.support;
public abstract class DataAccessUtils {
//...
public static <T> T requiredSingleResult(Collection<T> results)
throws IncorrectResultSizeDataAccessException {
int size = (results != null ? results.size() : 0);
if (size == 0) {
throw new EmptyResultDataAccessException(1);
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, size);
}
return results.iterator().next();
}
check it here : source
try {
String getVendorData = "select vendor_ID from vendor_login where vendor_ID= ? and password=?";
String name =null;
name = (String) jdbcTemplate.queryForObject(getVendorData,new Object[]{vendorlogin.getVendorLoginId(), vendorlogin.getPassWord()}, String.class);
} catch (EmptyResultDataAccessException e) {
return null;
}

how to load data to ignite cache when there is no ID when Implementing a cacheStore?

I m using ignite cache, I want to cache a view where the id is not relevant so implementing loadCache seems to be somehow tricky to me when there is no id!!!
How should I update the example below
public class CacheJdbcPersonStore extends CacheStoreAdapter<Long, Person> {
...
// This method is called whenever "IgniteCache.loadCache()" or
// "IgniteCache.localLoadCache()" methods are called.
#Override public void loadCache(IgniteBiInClosure<Long, Person> clo, Object... args) {
if (args == null || args.length == 0 || args[0] == null)
throw new CacheLoaderException("Expected entry count parameter is not provided.");
final int entryCnt = (Integer)args[0];
Connection conn = null;
try (Connection conn = connection()) {
try (PreparedStatement st = conn.prepareStatement("select * from PERSONS")) {
try (ResultSet rs = st.executeQuery()) {
int cnt = 0;
while (cnt < entryCnt && rs.next()) {
Person person = new Person(rs.getLong(1), rs.getString(2), rs.getString(3));
clo.apply(person.getId(), person);
cnt++;
}
}
}
}
catch (SQLException e) {
throw new CacheLoaderException("Failed to load values from cache store.", e);
}
}
...
}
clo.apply(person.getId(), person); this part is the issue in my logic my view doesn't have an ID
You need some unique ID to store data in Ignite. If there is nothing suitable in the actual data, your options are:
UUID.randomUUID()
Simple counter (id++) or LongAdder/AtomicLong - works only if you are loading from a single node
IgniteAtomicSequence - works across entire cluster

Hibernate HQL Projection Issue with Set Using AliasToBeanResultTransformer

I am having a problem with Hibernate HQL Projection using the AliasToBeanResultTransformer, basically the result I am trying to return isn't being mapped properly to the bean, here is the situation:
The HQL query that I am using is this:
select entity.categoryTypes as categoryTypes from nz.co.doltech.ims.server.entities.IncidentEntity entity where (entity.id = :id105019)
I want to get the CategoryType's from the IncidentEntity based on its join relationship. This works fine when I'm not attempting to use any transformer on it. categoryTypes is a Set and the transformer keeps trying to check the Method's parameter types and fails because instead of finding a CategoryTypeEntity it finds a java.util.Set as if its trying to map a single CategoryTypeEntity into the categoryTypes field. I would have thought that because its a Set it would pull the data out as a Set and then try map it to the categoryTypes field. Apparently not though.
#javax.persistence.Entity(name = "incidents")
#Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL)
public class IncidentEntity implements Entity {
...
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "incident_categorytype", joinColumns = {
#JoinColumn(name = "incident_id", nullable = false, updatable = false) },
inverseJoinColumns = {
#JoinColumn(name = "categorytype_id", nullable = false, updatable = false)
})
private Set<CategoryTypeEntity> categoryTypes = new HashSet<CategoryTypeEntity>();
...
public Set<CategoryTypeEntity> getCategoryTypes() {
return categoryTypes;
}
public void setCategoryTypes(Set<CategoryTypeEntity> categoryTypes) {
this.categoryTypes = categoryTypes;
}
}
Here is the call I make:
Query query = session.createQuery("select entity.categoryTypes as categoryTypes from nz.co.doltech.ims.server.entities.IncidentEntity entity " +
"where (entity.id = :id105019)")
query.setResultTransformer(Transformers.aliasToBean(IncidentEntity.class));
return query.list();
The exceptions I get are:
Caused by: org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of nz.co.doltech.ims.server.entities.IncidentEntity.categoryTypes
...
Caused by: java.lang.IllegalArgumentException: argument type mismatch
And the hibernate log message is:
Jun 27, 2014 12:32:11 AM org.hibernate.property.BasicPropertyAccessor$BasicSetter set
SEVERE: IllegalArgumentException in class: nz.co.doltech.ims.server.entities.IncidentEntity, setter method of property: categoryTypes
Jun 27, 2014 12:32:11 AM org.hibernate.property.BasicPropertyAccessor$BasicSetter set
SEVERE: expected type: java.util.Set, actual value: nz.co.doltech.ims.server.entities.CategoryTypeEntity
Using Hibernate 3.6.10
Can anyone see what is going on here? It really doesn't seem like normal behavior, perhaps I have done something wrong. Would appreciate any help I can get!
UPDATE: This is strange, not directly related to the issue. When I have hibernates use_query_cache property set to true I keep getting the projection result as null in the AliasToBeanResultTransformer (then the result returns as null (or [null, null, null] depending on how many are returned. I think this might be a bug? In regards to the issue at hand, when I remove the result transformer it returns 3 CategoryTypeEntites as expected. When its added I get one CategoryTypeEntity that's being processed in the Transformers transformTuple method. Really confused about both of these issues.
Cheers,
Ben
Manage to resolve this issue by rewriting the AliasToBeanResultTransformer class. It will not insert into a collection if the collection types match and the collections generic type match. I also found a great nested bean transformer make by samiandoni that will allow me to map nested projection values too :) Here is how I implemented it for anyone else having this same issue:
#SuppressWarnings({"serial","rawtypes"})
public class AliasToBeanResultTransformer implements ResultTransformer, Serializable {
// IMPL NOTE : due to the delayed population of setters (setters cached
// for performance), we really cannot properly define equality for
// this transformer
private final Class resultClass;
private boolean isInitialized;
private String[] aliases;
private Setter[] setters;
private Getter[] getters;
public AliasToBeanResultTransformer(Class resultClass) {
if ( resultClass == null ) {
throw new IllegalArgumentException( "resultClass cannot be null" );
}
isInitialized = false;
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
Object result;
try {
if ( ! isInitialized ) {
initialize( aliases );
}
else {
check( aliases );
}
result = resultClass.newInstance();
for ( int i = 0; i < aliases.length; i++ ) {
Setter setter = setters[i];
if ( setter != null ) {
Class paramType = setter.getMethod().getParameterTypes()[0];
if(paramType != null) {
Object obj = tuple[i];
// Check if parameter is a collection
if(!obj.getClass().equals(paramType) && isCollection(paramType)) {
insertToList(result, obj, getters[i], aliases[i]);
}
else {
setter.set( result, obj, null );
}
}
}
}
}
catch ( InstantiationException e ) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
return result;
}
#Override
public List transformList(List collection) {
return collection;
}
#SuppressWarnings("unchecked")
private boolean insertToList(Object result, Object obj, Getter getter, String alias) {
Class genClass;
try {
genClass = ReflectUtils.getGenericType(resultClass.getDeclaredField(alias));
// Check if the collection can take the obj
if(genClass.equals(obj.getClass())) {
Collection collection = (Collection) getter.get(result);
collection.add(obj);
return true;
}
} catch (NoSuchFieldException | SecurityException e) {}
return false;
}
private void initialize(String[] aliases) {
PropertyAccessor propertyAccessor = new ChainedPropertyAccessor(
new PropertyAccessor[] {
PropertyAccessorFactory.getPropertyAccessor( resultClass, null ),
PropertyAccessorFactory.getPropertyAccessor( "field" )
}
);
this.aliases = new String[ aliases.length ];
setters = new Setter[ aliases.length ];
getters = new Getter[ aliases.length ];
for ( int i = 0; i < aliases.length; i++ ) {
String alias = aliases[ i ];
if ( alias != null ) {
this.aliases[ i ] = alias;
setters[ i ] = propertyAccessor.getSetter( resultClass, alias );
getters[ i ] = propertyAccessor.getGetter( resultClass, alias );
}
}
isInitialized = true;
}
private void check(String[] aliases) {
if ( ! Arrays.equals( aliases, this.aliases ) ) {
throw new IllegalStateException(
"aliases are different from what is cached; aliases=" + Arrays.asList( aliases ) +
" cached=" + Arrays.asList( this.aliases ) );
}
}
private boolean isCollection(Class clazz) {
return Collection.class.isAssignableFrom(clazz);
}
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
AliasToBeanResultTransformer that = ( AliasToBeanResultTransformer ) o;
if ( ! resultClass.equals( that.resultClass ) ) {
return false;
}
if ( ! Arrays.equals( aliases, that.aliases ) ) {
return false;
}
return true;
}
public int hashCode() {
int result = resultClass.hashCode();
result = 31 * result + ( aliases != null ? Arrays.hashCode( aliases ) : 0 );
return result;
}
}
You will need to implement this RefectUtil method too:
public static Class<?> getGenericType(Field field) {
ParameterizedType type = (ParameterizedType) field.getGenericType();
return (Class<?>) type.getActualTypeArguments()[0];
}
Then you can make it work with samiandoni's transformer too (just ensure its using your edited AliasToBeanResultTransformer class):
/**
* #author samiandoni
*
*/
#SuppressWarnings("rawtypes")
public class AliasToBeanNestedResultTransformer implements ResultTransformer, Serializable {
private static final long serialVersionUID = -8047276133980128266L;
private final Class<?> resultClass;
public AliasToBeanNestedResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#SuppressWarnings("unchecked")
public Object transformTuple(Object[] tuple, String[] aliases) {
Map<Class<?>, List<?>> subclassToAlias = new HashMap<Class<?>, List<?>>();
List<String> nestedAliases = new ArrayList<String>();
try {
for (int i = 0; i < aliases.length; i++) {
String alias = aliases[i];
if (alias.contains(".")) {
nestedAliases.add(alias);
String[] sp = alias.split("\\.");
String fieldName = sp[0];
String aliasName = sp[1];
Class<?> subclass = resultClass.getDeclaredField(fieldName).getType();
if (!subclassToAlias.containsKey(subclass)) {
List<Object> list = new ArrayList<Object>();
list.add(new ArrayList<Object>());
list.add(new ArrayList<String>());
list.add(fieldName);
subclassToAlias.put(subclass, list);
}
((List<Object>)subclassToAlias.get(subclass).get(0)).add(tuple[i]);
((List<String>)subclassToAlias.get(subclass).get(1)).add(aliasName);
}
}
}
catch (NoSuchFieldException e) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
Object[] newTuple = new Object[aliases.length - nestedAliases.size()];
String[] newAliases = new String[aliases.length - nestedAliases.size()];
int i = 0;
for (int j = 0; j < aliases.length; j++) {
if (!nestedAliases.contains(aliases[j])) {
newTuple[i] = tuple[j];
newAliases[i] = aliases[j];
++i;
}
}
ResultTransformer rootTransformer = new AliasToBeanResultTransformer(resultClass);
Object root = rootTransformer.transformTuple(newTuple, newAliases);
for (Class<?> subclass : subclassToAlias.keySet()) {
ResultTransformer subclassTransformer = new AliasToBeanResultTransformer(subclass);
Object subObject = subclassTransformer.transformTuple(
((List<Object>)subclassToAlias.get(subclass).get(0)).toArray(),
((List<Object>)subclassToAlias.get(subclass).get(1)).toArray(new String[0])
);
PropertyAccessor accessor = PropertyAccessorFactory.getPropertyAccessor("property");
accessor.getSetter(resultClass, (String)subclassToAlias.get(subclass).get(2)).set(root, subObject, null);
}
return root;
}
#Override
public List transformList(List collection) {
return collection;
}
}

Hibernate PersistenceContext session Flush

i want to know when does hibernate fulshes the context session when i call session= session.getCurrentSession()
The thing is i have 2 methods in my dao calling getCurrentSession(), when i process the update making the call to getCurrentSession() the entitys are empty:
SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];...)
How can i make this entitys persist from the select method to the update method?
Here are my methods:
public List<SystemConfiguration> getListConfigurations() {
List<SystemConfiguration> lista = new ArrayList<SystemConfiguration>();
Session session = null;
Query query = null;
String sql = "from SystemConfiguration where description = :desc";
try {
/* BEFORE
session = SessionFactoryUtil.getInstance().getCurrentSession();
#SuppressWarnings("unused")
Transaction ta = session.beginTransaction(); */
//FOLLOWING LINE SOLVED THE PROBLEM
session = SessionFactoryUtil.getInstance().openSession();
query = session.createQuery(sql);
query.setString("desc", "configuracion");
lista = query.list();
return lista;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void updateConfigurations(List<SystemConfiguration> configs) throws Exception{
Session sess = null;
Transaction tx = null;
try {
//BEFORE
//sess = SessionFactoryUtil.getInstance().getCurrentSession();
//FOLLOWING LINE SOLVED THE PROBLEM
sess = SessionFactoryUtil.getInstance().openSession(new SystemConfigurationInterceptor());
tx = sess.beginTransaction();
for (SystemConfiguration sys : configs) {
sess.update(sys);
}
tx.commit();
} // try
catch (Exception e) {
e.printStackTrace();
if (tx != null && tx.isActive()) {
tx.rollback();
} // if
throw e;
}
}
And this is my interceptor:
public class SystemConfigurationInterceptor extends EmptyInterceptor {
private int updates;
private int creates;
private int loads;
public void onDelete(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
// do nothing
}
// This method is called when Entity object gets updated.
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof SystemConfiguration ) {
updates++;
for ( int i=0; i < propertyNames.length; i++ ) {
if ( "updated_at".equals( propertyNames[i] ) ) {
currentState[i] = new Timestamp(Calendar.getInstance().getTime().getTime());
return true;
}
}
}
return false;
}
public boolean onLoad(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof SystemConfiguration ) {
loads++;
}
return false;
}
// This method is called when Entity object gets created.
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof SystemConfiguration ) {
creates++;
for ( int i=0; i<propertyNames.length; i++ ) {
if ( "updated_at".equals( propertyNames[i] ) ) {
state[i] = new Timestamp(Calendar.getInstance().getTime().getTime());
return true;
}
}
}
return false;
}
public void afterTransactionCompletion(Transaction tx) {
if ( tx.wasCommitted() ) {
System.out.println("Creations: " + creates + ", Updates: " + updates +", Loads: " + loads);
}
updates=0;
creates=0;
loads=0;
}
Hibernate will flush when you tell it to and when the current transaction is "closed" (usually when the DB connection is returned to the pool somehow).
So the answer to your question depends on which framework you use. With Spring, the session is flushed when the outermost #Transactional method returns.
Your "solution" above will not work for long since it never closes the session. While it returns a result, it will leak a database connection so after a few calls, you will run out of connections.
Also your question doesn't really make sense. SELECT doesn't change objects, so they don't need to be "persisted" before you change them.
After changing them in updateConfigurations(), Hibernate can chose not to write them into the database immediately and just update the cache.
Eventually, if you configured everything correctly, Spring will commit the transaction and that will flush the cache. But when you use Spring, you should never create open and close sessions because it will mess with what Spring is doing.

How to call Java object from CDI bean

I have a CDI bean with Java object which I use to display profile data from Database:
Parent Bean
#Named("DCProfileTabGeneralController")
#ViewScoped
public class DCProfileTabGeneral implements Serializable
{
public DCObj dc;
public class DCObj
{
private int componentStatsId; // COMPONENTSTATSID NUMBER(38,0)
........
// Default Constructor
public DCObj(){};
public DCObj(int componentStatsId....)
{
this.componentStatsId = componentStatsId;
.......
}
public int getComponentStatsId()
{
return componentStatsId;
}
public void setComponentStatsId(int componentStatsId)
{
this.componentStatsId = componentStatsId;
}
....
}
// Getters ------------------------------------------------------------------------------------
public DCObj getdcData()
{
return dc;
}
#PostConstruct
public void initData() throws SQLException
{
initDBData();
}
// Generate data Object from Oracle
public void initDBData() throws SQLException
{
dc = new DCObj(result.getInt("COMPONENTSTATSID"),
.........
}
}
Validator
#Named("ValidatorDatacenterController")
#ViewScoped
public class ValidatorDatacenter implements Validator, Serializable
{
public ValidatorDatacenter()
{
}
#Inject
private DCProfileTabGeneral profileTabGeneral;
// Validate Datacenter Name
public void validateDatacenterName(FacesContext context, UIComponent component, Object value) throws ValidatorException, SQLException
{
int componentStatsId = -1;
if (profileTabGeneral != null)
{
DCObj dcData = profileTabGeneral.dc;
if (dcData != null)
{
componentStatsId = dcData.getComponentStatsId();
}
}
if (componentStatsId == -1)
{
return;
}
String l;
String s;
if (value != null && !(s = value.toString().trim()).isEmpty())
{
if (s.length() > 18)
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
" Value is too long! (18 digits max)", null));
}
if (ds == null)
{
throw new SQLException("Can't get data source");
}
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs;
int resComponentStatsId = -1;
try
{
conn = ds.getConnection();
// if componentsstatsid <> edited componentstatsid in jsf -> throw validator exception
ps = conn.prepareStatement("SELECT componentstatsid from COMPONENTSTATS where NAME = ?");
ps.setString(1, s);
rs = ps.executeQuery();
while (rs.next())
{
resComponentStatsId = rs.getInt(1);
}
if (resComponentStatsId != -1 && resComponentStatsId != componentStatsId)
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
" '" + s + "' is already in use!", null));
}
}
catch (SQLException x)
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
" SQL error!", null));
}
finally
{
if (ps != null)
{
ps.close();
}
if (conn != null)
{
conn.close();
}
}
}
else
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
" This field cannot be empty!", null));
}
}
}
I have a custom validator which checks the input values from the profile page into the Database. I tested to get the Java object from the parent page using #Inject and to pass the Ojject to the validator. It turns out that I get empty Java object every time when I use #Inject.
I also tested to get Int using CDI. It works but when I again tested to get the Java Object again I get empty Object.
Can you tell me what is the proper way to call a Java Object from CDI bean? Why I cannot get Java object from CDI bean?
If I recall correctly CDI injection will not work with a validator. Use advanced from Myfaces CODI as the JSF-module from deltaspike is not ready yet. https://cwiki.apache.org/EXTCDI/jsf-usage.html
Or go for deltaspike and use the BeanProvider to get your instance.
BeanProvider.getContextualReference(DCProfileTabGeneral .class, false);

Categories