Flex 3.5 compile error

I encountered the following flex compile-time errors (using flex sdk 3.5.x):

1046: Type was not found or was not a compile-time constant: ModelLocator.

1120: Access of undefined property be.

while trying to compile an ActionScript3 file containing:

...
private var model1:be.myPackage1.ModelLocator = 
   be.myPackage1.ModelLocator.getInstance();		
private var model2:be.myPackage2.ModelLocator = 
   be.myPackage2.ModelLocator.getInstance();
...


I had to import these classes explicitly in order to make the error go away.

...
import be.myPackage1.ModelLocator
import be.myPackage2.ModelLocator
...

The weird thing is that I copied the variable assignments from a class that does compile, even without the explicit imports.

DbUnit NoSuchColumnException using Oracle with synonym chain.

I stumbled on the is problem using DbUnit 2.4.8 and Oracle driver 11.1.0.6.0 for table names that are actually synonyms pointing to an other synonym pointing to a view in an other schema. (long story...)

WARN [2011-08-24 08:30:40] [user=] (DatabaseTableMetaData.java:getColumns:348) - No columns found for table 'XXX_TABLE' that are supported by dbunit. Will return an empty column list

org.dbunit.dataset.NoSuchColumnException: XXX_TABLE.XXX_ID -  (Non-uppercase input column: XXX_ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
	at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)
	at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:89)
	at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:140)


It looks like OracleDatabaseMetaData doesn't take into account chained synonyms, even with "SYNONYM" included in the dbUnit table types config property (DatabaseConfig.PROPERTY_TABLE_TYPE).

To work around this problem, I extended the DefaultMetadataHandler to resolve the actual schema_name/table_name when needed.

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.dbunit.database.DefaultMetadataHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * Solves the problem where Dbunit throws a NoSuchColumnException because it cannot resolve the column names through
 * a chain of synonyms.
 */
public class OracleSynonymAwareMetaDataHandler extends DefaultMetadataHandler {

    public static final Logger logger = LoggerFactory.getLogger(OracleSynonymAwareMetaDataHandler.class);

    private final Map<TableInfo, TableInfo> synonymMap;
    private final SimpleJdbcOperations simpleJdbcOperations;

    private static final String SQL_SELECT_USER_SYNONYM =
            "\n with filter1 as (  " +
                    "\n select connect_by_root synonym_name root_synonym_name,  " +
                    "\n 	   connect_by_root table_owner root_table_owner,  " +
                    "\n 	   level lvl,  " +
                    "\n 	   syn.*  " +
                    "\n from user_synonyms syn  " +
                    "\n connect by synonym_name = prior table_name and (table_owner != prior table_owner)  " +
                    "\n start with synonym_name = :p_synonym_name and table_owner = :p_schema_name   " +
                    "\n ), filter2 as (  " +
                    "\n select filter1.*,  " +
                    "\n 	   max(lvl) over (PARTITION BY root_synonym_name, root_table_owner) max_lvl  " +
                    "\n from filter1  " +
                    "\n )  " +
                    "\n select table_owner,  " +
                    "\n 	   table_name  " +
                    "\n from filter2  " +
                    "\n where lvl = max_lvl  ";


    public OracleSynonymAwareMetaDataHandler(SimpleJdbcOperations simpleJdbcOperations) {
        synonymMap = new HashMap<TableInfo, TableInfo>();
        this.simpleJdbcOperations = simpleJdbcOperations;
    }

    @Override
    public ResultSet getColumns(final DatabaseMetaData databaseMetaData,
                                final String schemaName,
                                final String tableName)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.getColumns(databaseMetaData, tableInfo.getSchemaName(), 
                                tableInfo.getTableName());
    }

    @Override
    public boolean matches(ResultSet columnsResultSet,
                           String catalog,
                           String schemaName,
                           String tableName,
                           String column,
                           boolean caseSensitive)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.matches(columnsResultSet, catalog, tableInfo.getSchemaName(), 
                             tableInfo.getTableName(), column, caseSensitive);
    }

    @Override
    public ResultSet getPrimaryKeys(DatabaseMetaData metaData,
                                    String schemaName,
                                    String tableName)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.getPrimaryKeys(metaData, tableInfo.getSchemaName(), 
                                    tableInfo.getTableName());
    }

    /**
     * returns the ACTUAL schemaName and tableName for the provided values
     */
    private TableInfo getTableInfo(final String schemaName, final String tableName) {

        logger.debug("getTableInfo - schemaName: {}, tableName: {}", schemaName, tableName);

        TableInfo requestTableInfo = new TableInfo(schemaName, tableName);

        if (synonymMap.containsKey(requestTableInfo)) {
            return synonymMap.get(requestTableInfo);
        } else {
            TableInfo actualTableInfo = (TableInfo) DataAccessUtils.singleResult(
                simpleJdbcOperations.getNamedParameterJdbcOperations().query(
                    SQL_SELECT_USER_SYNONYM,
                    new HashMap<String, Object>() {{
                        put("p_synonym_name", tableName);
                        put("p_schema_name", schemaName);
                    }},
                    new ParameterizedRowMapper<tableinfo>() {
                        @Override
                        public TableInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                            int ndx = 0;
                            return new TableInfo(
                                    rs.getString(++ndx)
                                    , rs.getString(++ndx)
                            );
                        }
                    }
            ));

            if (actualTableInfo == null) {
                actualTableInfo = requestTableInfo;
            }

            synonymMap.put(requestTableInfo, actualTableInfo);

            return actualTableInfo;
        }
    }


    private static class TableInfo {
        private final String schemaName;
        private final String tableName;

        private TableInfo(String schemaName, String tableName) {
            this.schemaName = schemaName;
            this.tableName = tableName;
        }

        public String getSchemaName() {
            return schemaName;
        }

        public String getTableName() {
            return tableName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof TableInfo)) return false;

            TableInfo that = (TableInfo) o;

            return EqualsBuilder.reflectionEquals(this, that);
        }

        @Override
        public int hashCode() {
            return HashCodeBuilder.reflectionHashCode(this);
        }

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
        }
    }
}


This OracleSynonymAwareMetaDataHandler class can be configured into dbUnit using the DatabaseConfig.PROPERTY_METADATA_HANDLER config property.

iDatabaseConnection.getConfig()
    .setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, 
        oracleSynonymAwareMetaDataHandlerInstance );




The hierarchical (oracle) query I wrote is a bit tricky, but it returns the 'deepest' synonym on the fly. The same result could be achieved by recursively retrieving a single synonym at a time until no result is found.

with filter1 as (
select connect_by_root synonym_name root_synonym_name,
	   connect_by_root table_owner root_table_owner,
	   level lvl,	   	    
	   syn.*	     
from user_synonyms syn
connect by synonym_name = prior table_name and (table_owner != prior table_owner)
start with synonym_name = :p_synonym_name and table_owner = :p_schema_name 
), filter2 as (
select filter1.*,
	   max(lvl) over (PARTITION BY root_synonym_name, root_table_owner) max_lvl
from filter1
)
select table_owner,
	   table_name
from filter2
where lvl = max_lvl

Installing eclipse 3.7 (indigo) on Ubuntu

Installing an alternative eclipse as the one provided through the software center is not that difficult.

Go the the eclipse download page, and download the package that suits you most. I went for the 64 bit JEE version: eclipse-jee-indigo-linux-gtk-x86_64.tar.gz.

Next, open a terminal and execute the folowing commands:

tar zxfv eclipse-jee-indigo-linux-gtk-x86_64.tar.gz

mv eclipse eclipse-3.7

sudo mv eclipse-3.7 /opt

cd /opt

sudo chown -R root:root eclipse-3.7

sudo ln -s /opt/eclipse-3.7/eclipse /usr/bin/eclipse

The same procedure works for other versions as well.

Maven archetype-plugin

I wanted to try-out Maven 3 and Appfuse 2.1 today. Unfortunatly, I lost some time due to a problem with the Archetype-plugin, and me being behind proxy.

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-spring-archetype -DarchetypeVersion=2.1.0-M2-SNAPSHOT -DgroupId=be.fatsu -DartifactId=test1 -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse


as generated by the appfuse quickstart page fails with TransferFailedException: Error transferring file.

The Archetype plugin apparently doesn't take into account the proxy configuration from the maven settings, as explained in the related issue: ARCHETYPE-202.

The easiest way around this is by setting system variables:

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-spring-archetype -DarchetypeVersion=2.1.0-M2-SNAPSHOT -DgroupId=be.fatsu -DartifactId=test1 -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse -Dhttp.proxyHost=xxx.xxx.xxx.xxx -Dhttp.proxyPort=xxxx -Dhttp.proxyUser=xxxxxxx -Dhttp.proxyPassword=xxxxxxx

Specific Cobertura version in Maven-cobertura-plugin

I found this blog post by Brian Fox explaining how to override a plugin's dependencies.
This allowed me to configure the maven-cobertura-plugin to use a specific cobertura version (1.9.1.1 being the latest one available in the central maven repository), instead of the one configured by the plugin itself (1.9).
As stated by Brian, as long as the newly introduced version's API is compatible with the original one, there should be no problem.

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>net.sourceforge.cobertura</groupId>
<artifactId>cobertura</artifactId>
<version>1.9.1.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>

Maven: Spring-Test 2.5.x & JUnit 4

I ran into this weird problem today while setting up an integration-testing module in my maven project: The Surefire-plugin seemed to ignore the JUnit4 annotations.
I found a Maven-Surefire issue (SUREFIRE-448) describing the same problem, but it is marked as irreproducible and proposes no solution.
After looking into the debug information (mvn clean test -X > log.txt), it turns out that Spring-Test has a dependency on JUnit 3.8.1, and this is causing my test classes to run as JUnit3 instead of JUnit4.
To fix this, simply exclude JUnit from the Spring-Test dependency:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.6</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>

initializing static final Collection/Map in one statement

Initializing a static final (unmodifiable) Map:

private final static Map<String,String> map = Collections.unmodifiableMap(new HashMap<String,String>() {
{
put("key1", "value1");
put("key2", "value2");
}
});



Initializing a static final (unmodifiable) Collection:

private final static Set<String> set = Collections.unmodifiableSet(new HashSet<String>() {
{
add("value1");
add("value2");
}
});

Hibernate GenericEnumUserType

Hibernate usertype for getting/setting a custom value instead of using @Enumerated(EnumType.STRING) or @Enumerated(EnumType.Ordinal)


UserType source:

package example.usertype;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.type.NullableType;
import org.hibernate.type.TypeFactory;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;

/**
* generic enum user type based on: http://www.hibernate.org/272.html
*
* @param enumClass
* @param identifierMethod
* @param valueOfMethod
*/
public class GenericEnumUserType implements UserType, ParameterizedType {
private static final String DEFAULT_IDENTIFIER_METHOD_NAME = "name";
private static final String DEFAULT_VALUE_OF_METHOD_NAME = "valueOf";

@SuppressWarnings("unchecked")
private Class<? extends Enum> enumClass;
private Class<?> identifierType;
private Method identifierMethod;
private Method valueOfMethod;
private NullableType type;
private int[] sqlTypes;

public void setParameterValues(Properties parameters) {
String enumClassName = parameters.getProperty("enumClass");
try {
enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
} catch (ClassNotFoundException cfne) {
throw new HibernateException("Enum class not found", cfne);
}

String identifierMethodName = parameters.getProperty(
"identifierMethod", DEFAULT_IDENTIFIER_METHOD_NAME);

try {
identifierMethod = enumClass.getMethod(identifierMethodName,
new Class[0]);
identifierType = identifierMethod.getReturnType();
} catch (Exception e) {
throw new HibernateException("Failed to obtain identifier method",
e);
}

type = (NullableType) TypeFactory.basic(identifierType.getName());

if (type == null)
throw new HibernateException("Unsupported identifier type "
+ identifierType.getName());

sqlTypes = new int[] { type.sqlType() };

String valueOfMethodName = parameters.getProperty("valueOfMethod",
DEFAULT_VALUE_OF_METHOD_NAME);

try {
valueOfMethod = enumClass.getMethod(valueOfMethodName,
new Class[] { identifierType });
} catch (Exception e) {
throw new HibernateException("Failed to obtain valueOf method", e);
}
}

@SuppressWarnings("unchecked")
public Class returnedClass() {
return enumClass;
}

public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
Object identifier = type.get(rs, names[0]);
if (identifier == null) {
return null;
}

// fix for fixed length char datatype (db2)
if (identifier instanceof String) {
identifier = ((String) identifier).trim();
}

Object value;
try {
value = valueOfMethod
.invoke(enumClass, new Object[] { identifier });
} catch (Exception e) {
throw new HibernateException(
"Exception while invoking valueOf method '"
+ valueOfMethod.getName() + "' of "
+ "enumeration class '" + enumClass + "'", e);
}

if (value == null) {
throw new HibernateException(
"Impossible to translate identifier-value '" + identifier
+ "' to enum of type '" + enumClass + "'");
}

return value;

}

public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {

if (value == null) {
st.setNull(index, type.sqlType());
} else {
Object identifier;
try {
identifier = identifierMethod.invoke(value, new Object[0]);
} catch (Exception e) {
throw new HibernateException(
"Exception while invoking identifierMethod '"
+ identifierMethod.getName() + "' of "
+ "enumeration class '" + enumClass + "'", e);
}

if (identifier == null) {
throw new HibernateException(
"Disallowed to update/insert null identifier-value for non-null enum-value of type '"
+ enumClass + "'");
}

type.set(st, identifier, index);
}

}

public int[] sqlTypes() {
return sqlTypes;
}

public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}

public Object deepCopy(Object value) throws HibernateException {
return value;
}

public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}

public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}

public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}

public boolean isMutable() {
return false;
}

public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
}


Enum source:

package example.model;

import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

public enum Direction {

INCOMING('I'), //
OUTGOING('O'); //

private static final Map<Character, Direction> idMap = new HashMap<Character, Direction>();

static {
for (Direction direction : EnumSet.allOf(Direction.class)) {
idMap.put(direction.getId(), direction);
}
}

private final Character id;

private Direction(Character id) {
this.id = id;
}

public static Direction valueById(Character id) {
return idMap.get(id);
}

public Character getId() {
return id;
}

}


Usage:

@Type(type = "example.usertype.GenericEnumUserType", parameters = {
@Parameter(name = "enumClass", value = "example.model.Direction"),
@Parameter(name = "identifierMethod", value = "getId"),
@Parameter(name = "valueOfMethod", value = "valueById") })
@Column(name = "DIRECTION", nullable = false, length = 1)
public Direction getDirection() {
return this.direction;
}

public void setDirection(Direction direction) {
this.direction = direction;
}

Hibernate StringTrimUserType

Use for fixed length column definitions. (e.g. DB2 'char' type)

Source:

package example.usertype;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.usertype.UserType;

/**
*
* based on www.hibernate.org/388.html
*/

public class StringTrimUserType implements UserType {

/**
*
* default constructor
*/

public StringTrimUserType() {
}

/**
*
* @see org.hibernate.usertype.UserType#sqlTypes()
*/

public int[] sqlTypes() {
return new int[] { Types.CHAR };
}

/**
*
* @see org.hibernate.usertype.UserType#returnedClass()
*/

@SuppressWarnings("unchecked")
public Class returnedClass() {
return String.class;
}

/**
*
* @see org.hibernate.usertype.UserType#equals(java.lang.Object,
* java.lang.Object)
*/

public boolean equals(Object x, Object y) {
return (x == y) || (x != null && y != null && (x.equals(y)));
}

/**
*
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
* java.lang.String[], java.lang.Object)
*/

public Object nullSafeGet(ResultSet inResultSet, String[] names, Object o) throws SQLException {

String val = (String) Hibernate.STRING.nullSafeGet(inResultSet, names[0]);
return val == null ? null : val.trim();
}

/**
*
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
* java.lang.Object, int)
*/

public void nullSafeSet(PreparedStatement inPreparedStatement, Object o,
int i)

throws SQLException {

String val = (String) o;
inPreparedStatement.setString(i, val);
}

/**
*
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/

public Object deepCopy(Object o) {
if (o == null) {
return null;
}
return new String(((String) o));
}

/**
*
* @see org.hibernate.usertype.UserType#isMutable()
*/

public boolean isMutable() {
return false;
}

/**
*
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable,
* java.lang.Object)
*/

public Object assemble(Serializable cached, Object owner) {
return cached;
}

/**
*
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
*/

public Serializable disassemble(Object value) {
return (Serializable) value;
}

/**
*
* @see org.hibernate.usertype.UserType#replace(java.lang.Object,
* java.lang.Object, java.lang.Object)
*/

public Object replace(Object original, Object target, Object owner) {
return original;
}

/**
*
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
*/

public int hashCode(Object x) {
return x.hashCode();
}

}



Usage:

@Column(name = "CMODULE", unique = true, nullable = false, length = 10, columnDefinition = "char")
@Type(type = "example.usertype.StringTrimUserType")
public String getModuleCode() {
return this.moduleCode;
}

public void setModuleCode(String moduleId) {
this.moduleCode = moduleId;
}

@EJB injection in JSF managed beans on glassfish with myfaces

I was trying to get @EJB dependency to work on my JSF managed beans. MyFaces Tomahawk on a Glassfish v2 app server. I kept getting NullPointerExceptions because the injection didn't happen...

Turns out it was failing to inject the ejb implementations because my webapp was trying to use the MyFaces jsf implementation next to the sun RI implementation shipped with Glassfish.

So, make sure not both the RI implementation (provided by glassfish), and myFaces implementation are active!

I prevented the myFaces implementation from loading by commenting the StartupServletContextListener in WEB-INF/web.xml (2.5 headers):