I'm just starting out using abstract types. I'm running into an error that I'm not able to fully understand. Here is some of my code for some BACKGROUND
abstract class DbfReader( fileName: String )
{
type DBFDataType <:Any
type Key <:Any
type Value <:Any
abstract class FieldMapping
{
type FieldType
def acronym: Key
def longName: Key
def fieldNum: Int
def getField: FieldType
def getFieldLength: Int
}
def fieldMappings: Map[ Key, FieldMapping ]
def getFieldCount: Int
def hasRecord(): Boolean
def getRecord(): DBFDataType
def getFieldVal( fieldName: Key )( rowData: DBFDataType ): Value
protected def createFieldMapping( fieldAcro: Key,
fieldLongName: Key,
fieldPosition: Int ): FieldMapping
....
}
THe Abstract class DbfReader is meant to be an abstract wrapper to different DBF (Data base file ) reading Libraries i'm trying out. The abstract class has an inner class of FieldMapping (table meta data which has a abstract type FieldType
which is meant to be a placeholder for the underlying libraries representation of a Data base Field. THe routine getField
in the inner class returns a reference of this type.
Following is a concerete implementation of this abstract class: EVEN MORE BACKGROUND
class MyDBFReader( fileName: String, fmap: List[( String, String, Int )] ) extends DbfReader( fileName )
{
type DBFDataType = Array[Object]
type Key = String
type Value = String
val dbReader = new jdbf.DBFReader( new java.io.FileInputStream( theFile ) )
val fieldMappings = addFieldMappings(fmap)(Map())
case class InnerFieldMapping( acronym: Key, longName: Key, fieldNum: Int) extends FieldMapping
{
type FieldType = jdbf.JDBField
override def getField: jdbf.JDBField = dbReader.getField( fieldNum )
def getFieldLength = getField.getLength
}
def getFieldCount = dbReader.getFieldCount
def hasRecord = dbReader.hasNextRecord
def getRecord = dbReader.nextRecord
def createFieldMapping( fieldAcro: String, fieldLongName: String, fieldPosition: Int ) = InnerFieldMapping( fieldAcro, fieldLongName, fieldPosition )
def getFieldVal( fieldName: Key )( rowData: DBFDataType ) = {
if( fieldMappings.keySet.contains( fieldName ) ) stringer( rowData( fieldMappings( fieldName ).fieldNum - 1 ) )
else
throw new NoSuchElementException( "Key " + fieldName + " not Found" )
}
private def stringer( r: Object ) = r.asInstanceOf[String].trim
}
The trouble I'm running into is when I try to call getField from InnerFieldMapping which extends the abstract Field mapping. I'm trying this in a unit test like this:
WHERE THE PROBLEM HAPPENS
class MyDBFSuite extends FunSuite {
val fileName = "/Users/Me/api11bdb.dbf"
val dbf = new MyDBFReader( fileName, DbfReader.SchoolFieldMapping )
test( "Dbf should have 150 fields" )
{
assert( dbf.getFieldCount === 150 )
}
test( "Should read a record" )
{
assert( dbf.hasRecord === true )
assert( dbf.getRecord.size === 150 )
}
test( "Should Get a Field" )
{
println( dbf.fieldMappings.head._2.getField.getType )
//assert( dbf.fieldMappings.head._2.getField.getType === "S" )
}
In the last test ( either with the assert enabled or in the println ), whenever I try to access getType which is a routine in DBFField
which is what I expect from the inner class InnerFieldMapping
routine getField. In the abstract glass the routine specifies a return type of FieldType
, which I implement in the concrete class as jdbf.JDBFField
However the compiler says: THE PROBLEM
src/test/scala/ChinaDBFTestSuite.scala:23: value getType is not a member of MyDBFSuite.this.dbf.FieldMapping#FieldType
[error] println( dbf.fieldMappings.head._2.getField.getType )
[error] ^
In the other test I call the outer class routine getRecord which in its abstract class returns the abstract type. THe compiler had no problem there. Looking at the error message it seems that it expects a the FieldType to comply with the inner abstract class definition. I mean I would exect it to lookfor a MyDBFSuite.this.dbg.InnerFieldMapping.FieldType. Am I doing something inherently wrong here ?
EDIT: Thanks a lot for the answer. As a follow up, I also have a question about overriding? I notice that in the scala book methods returning abstract types are overriden in the sub-types, however I don't do this here and the compiler doesn't complain about missing implementations when instantiating the subtypes. Why is the override tag needed in the subclass method when the return type of the method is an abstract type ( as defined in the base class )?
getClass
? – 4lex1v