Converting ShapefileDataStore to JDBCDataStore fails with name change

217 views Asked by At
// Given
println(shpDataStore)
//ShapefileDataStore [file=file:/opt/c_1970-01-01T00-00-00.shp, charset=ISO-8859-1, timeZone=sun.util.calendar.ZoneInf [id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null], memoryMapped=false, bufferCachingEnabled=true, indexed=true, fidIndexed=true]

println(jdbcDataStore)
// org.geotools.jdbc.JDBCDataStore@4371a490

// Works
val features = shpDataStore.getFeatureSource(sourceTypeName).getFeatures
val featureType = features.getSchema
val featureTypeName = featureType.getName.getLocalPart

jdbcDataStore.createSchema(featureType)

val newType = jdbcDataStore.getSchema(featureTypeName)

val reTypedSFC = new TypeUpdatingFeatureCollection(features, newType)

val fs: FeatureStore[SimpleFeatureType, SimpleFeature] = jdbcDataStore.getFeatureSource(featureTypeName).asInstanceOf[FeatureStore[SimpleFeatureType, SimpleFeature]]

fs.addFeatures(reTypedSFC)


// Doesn't work
val features = shpDataStore.getFeatureSource(sourceTypeName).getFeatures
val featureName = "newName"
val originalFeatureType = features.getSchema
val sftBuilder = new SimpleFeatureTypeBuilder()
sftBuilder.init(originalFeatureType)
sftBuilder.setName(featureName)
val featureType = sftBuilder.buildFeatureType()

val featureTypeName = featureType.getName.getLocalPart

jdbcDataStore.createSchema(featureType)

val newType = jdbcDataStore.getSchema(featureTypeName)

val reTypedSFC = new TypeUpdatingFeatureCollection(features, newType)

val fs: FeatureStore[SimpleFeatureType, SimpleFeature] =
      jdbcDataStore.getFeatureSource(featureTypeName).asInstanceOf[FeatureStore[SimpleFeatureType, SimpleFeature]]

fs.addFeatures(reTypedSFC)

// Output is
//java.lang.IllegalArgumentException: Value c_1970-01-01T00-00-00.1 illegal for type java.lang.Integer
//        at org.geotools.jdbc.JDBCDataStore.decodeFID(JDBCDataStore.java:1890)
//        at org.geotools.jdbc.JDBCDataStore.insert(JDBCDataStore.java:1523)

UPDATE:

I tried

val f = shpDataStore.getFeatureSource(sourceTypeName).getFeatures
val ty = f.getSchema
val builder = new SimpleFeatureBuilder(ty)
val features = new DefaultFeatureCollection()
f.features().foreach { j =>
  builder.init(j)
  features.add(builder.buildFeature(null))
  builder.reset()
}

but I still get

fs.addFeatures(reTypedSFC) java.lang.IllegalArgumentException: Value fid--31eafd14_14a112b8f13_-6cbb illegal for type java.lang.Integer at org.geotools.jdbc.JDBCDataStore.decodeFID(JDBCDataStore.java:1890)

2

There are 2 answers

1
Ian Turton On

The problem is that with a shapefile the feature identifier (FID) is a string containing some random stuff (filename, date, hashcode of feature etc). While in a database it is usually based on the primary key if defined.

So you need to replace the fid of your feature with NULL so that the JDBCStore can create a new one when you add it to the table. Or change your table to accept strings in the ID column.

0
crenshaw-dev On

This, inspired by Ian's answer and a little research of my own, seems to resolve the issue.

val builder = new SimpleFeatureBuilder(simpleFeature.getFeatureType)
builder.init(simpleFeature)
builder.featureUserData(Hints.USE_PROVIDED_FID, false)
val featureNoId: SimpleFeature = builder.buildFeature(null)

Despite passing id=null to buildFeature, you still have to set the USE_PROVIDED_FID hint to false.

This works, I believe, because of this check in geotools source:

// pass through the fid if the user asked so
boolean useExisting =
    Boolean.TRUE.equals(feature.getUserData().get(Hints.USE_PROVIDED_FID));
if (getQueryCapabilities().isUseProvidedFIDSupported() && useExisting) {
    ((FeatureIdImpl) toWrite.getIdentifier()).setID(feature.getID());
}

But it does mean you can't use the feature id to prevent duplicates.