use of org.apache.sis.feature.DefaultFeatureType in project sis by apache.
the class FeatureTypeBuilderTest method testAddAnonymousIdentifier.
/**
* Tests {@link FeatureTypeBuilder#addAttribute(Class)} where one attribute is an identifier that already has
* the {@code "sis:identifier"} name. This is called "anonymous" because identifiers with an explicit name in
* the data file should use that name instead in the feature type.
*/
@Test
@DependsOnMethod("testAddIdentifierAndGeometry")
public void testAddAnonymousIdentifier() {
final FeatureTypeBuilder builder = new FeatureTypeBuilder();
assertSame(builder, builder.setName("City"));
builder.addAttribute(String.class).setName(AttributeConvention.IDENTIFIER_PROPERTY).addRole(AttributeRole.IDENTIFIER_COMPONENT);
builder.addAttribute(Integer.class).setName("population");
final DefaultFeatureType type = builder.build();
final Iterator<? extends AbstractIdentifiedType> it = type.getProperties(true).iterator();
final AbstractIdentifiedType a0 = it.next();
final AbstractIdentifiedType a1 = it.next();
assertFalse("properties count", it.hasNext());
assertEquals("name", AttributeConvention.IDENTIFIER_PROPERTY, a0.getName());
assertEquals("type", String.class, ((DefaultAttributeType<?>) a0).getValueClass());
assertEquals("name", "population", a1.getName().toString());
assertEquals("type", Integer.class, ((DefaultAttributeType<?>) a1).getValueClass());
}
use of org.apache.sis.feature.DefaultFeatureType in project sis by apache.
the class FeatureTypeBuilderTest method testAddAttribute.
/**
* Tests {@link FeatureTypeBuilder#addAttribute(Class)}.
*/
@Test
@DependsOnMethod("testInitialization")
public void testAddAttribute() {
final FeatureTypeBuilder builder = new FeatureTypeBuilder();
assertSame(builder, builder.setName("myScope", "myName"));
assertSame(builder, builder.setDefinition("test definition"));
assertSame(builder, builder.setDesignation("test designation"));
assertSame(builder, builder.setDescription("test description"));
assertSame(builder, builder.setAbstract(true));
builder.addAttribute(String.class).setName("name");
builder.addAttribute(Integer.class).setName("age");
builder.addAttribute(Point.class).setName("location").setCRS(HardCodedCRS.WGS84);
builder.addAttribute(Double.class).setName("score").setDefaultValue(10.0).setMinimumOccurs(5).setMaximumOccurs(50);
final DefaultFeatureType type = builder.build();
assertEquals("name", "myScope:myName", type.getName().toString());
assertEquals("definition", "test definition", type.getDefinition().toString());
assertEquals("description", "test description", type.getDescription().toString());
assertEquals("designation", "test designation", type.getDesignation().toString());
assertTrue("isAbstract", type.isAbstract());
final Iterator<? extends AbstractIdentifiedType> it = type.getProperties(true).iterator();
final DefaultAttributeType<?> a0 = (DefaultAttributeType<?>) it.next();
final DefaultAttributeType<?> a1 = (DefaultAttributeType<?>) it.next();
final DefaultAttributeType<?> a2 = (DefaultAttributeType<?>) it.next();
final DefaultAttributeType<?> a3 = (DefaultAttributeType<?>) it.next();
assertFalse("properties count", it.hasNext());
assertEquals("name", "name", a0.getName().toString());
assertEquals("name", "age", a1.getName().toString());
assertEquals("name", "location", a2.getName().toString());
assertEquals("name", "score", a3.getName().toString());
assertEquals("valueClass", String.class, a0.getValueClass());
assertEquals("valueClass", Integer.class, a1.getValueClass());
assertEquals("valueClass", Point.class, a2.getValueClass());
assertEquals("valueClass", Double.class, a3.getValueClass());
assertEquals("minimumOccurs", 1, a0.getMinimumOccurs());
assertEquals("minimumOccurs", 1, a1.getMinimumOccurs());
assertEquals("minimumOccurs", 1, a2.getMinimumOccurs());
assertEquals("minimumOccurs", 5, a3.getMinimumOccurs());
assertEquals("maximumOccurs", 1, a0.getMaximumOccurs());
assertEquals("maximumOccurs", 1, a1.getMaximumOccurs());
assertEquals("maximumOccurs", 1, a2.getMaximumOccurs());
assertEquals("maximumOccurs", 50, a3.getMaximumOccurs());
assertEquals("defaultValue", null, a0.getDefaultValue());
assertEquals("defaultValue", null, a1.getDefaultValue());
assertEquals("defaultValue", null, a2.getDefaultValue());
assertEquals("defaultValue", 10.0, a3.getDefaultValue());
assertFalse("characterizedByCRS", AttributeConvention.characterizedByCRS(a0));
assertFalse("characterizedByCRS", AttributeConvention.characterizedByCRS(a1));
assertTrue("characterizedByCRS", AttributeConvention.characterizedByCRS(a2));
assertFalse("characterizedByCRS", AttributeConvention.characterizedByCRS(a3));
}
use of org.apache.sis.feature.DefaultFeatureType in project sis by apache.
the class FeatureTypeBuilderTest method testBuildCache.
/**
* Verifies that {@code build()} method returns the previously created instance when possible.
* See {@link AttributeTypeBuilder#build()} javadoc for a rational.
*/
@Test
@DependsOnMethod("testAddAttribute")
public void testBuildCache() {
final FeatureTypeBuilder builder = new FeatureTypeBuilder().setName("City");
final DefaultAttributeType<String> name = builder.addAttribute(String.class).setName("name").build();
final DefaultFeatureType city = builder.build();
assertSame("Should return the existing AttributeType.", name, city.getProperty("name"));
assertSame("Should return the existing FeatureType.", city, builder.build());
assertSame("Should return the existing AttributeType since we didn't changed anything.", name, builder.getProperty("name").build());
assertNotSame("Should return a new AttributeType since we changed something.", name, builder.getProperty("name").setDescription("Name of the city").build());
assertNotSame("Should return a new FeatureType since we changed an attribute.", city, builder.build());
}
use of org.apache.sis.feature.DefaultFeatureType in project sis by apache.
the class FeatureTypeBuilderTest method testAddAnonymousGeometry.
/**
* Tests {@link FeatureTypeBuilder#addAttribute(Class)} where one attribute is a geometry that already has
* the {@code "sis:geometry"} name. This is called "anonymous" because geometries with an explicit name in
* the data file should use that name instead in the feature type.
*/
@Test
@DependsOnMethod("testAddIdentifierAndGeometry")
public void testAddAnonymousGeometry() {
final FeatureTypeBuilder builder = new FeatureTypeBuilder();
assertSame(builder, builder.setName("City"));
builder.addAttribute(Point.class).setName(AttributeConvention.GEOMETRY_PROPERTY).addRole(AttributeRole.DEFAULT_GEOMETRY);
builder.addAttribute(Integer.class).setName("population");
final DefaultFeatureType type = builder.build();
final Iterator<? extends AbstractIdentifiedType> it = type.getProperties(true).iterator();
final AbstractIdentifiedType a0 = it.next();
final AbstractIdentifiedType a1 = it.next();
final AbstractIdentifiedType a2 = it.next();
assertFalse("properties count", it.hasNext());
assertEquals("name", AttributeConvention.ENVELOPE_PROPERTY, a0.getName());
assertEquals("name", AttributeConvention.GEOMETRY_PROPERTY, a1.getName());
assertEquals("type", Point.class, ((DefaultAttributeType<?>) a1).getValueClass());
assertEquals("name", "population", a2.getName().toString());
assertEquals("type", Integer.class, ((DefaultAttributeType<?>) a2).getValueClass());
}
use of org.apache.sis.feature.DefaultFeatureType in project sis by apache.
the class FeatureTypeBuilder method build.
/**
* Builds the feature type from the information and properties specified to this builder.
* One of the {@code setName(…)} methods must have been invoked before this {@code build()} method (mandatory).
* All other methods are optional, but some calls to a {@code add} method are usually needed.
*
* <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed to the
* {@code org.opengis.feature.FeatureType} interface. This change is pending GeoAPI revision.</div>
*
* <p>If a feature type has already been built and this builder state has not changed since the
* feature type creation, then the previously created {@code FeatureType} instance is returned.</p>
*
* @return the feature type.
* @throws IllegalStateException if the builder contains inconsistent information.
*
* @see #clear()
*/
@Override
public DefaultFeatureType build() throws IllegalStateException {
if (feature == null) {
/*
* Creates an initial array of property types with up to 3 slots reserved for sis:identifier, sis:geometry
* and sis:envelope operations. At first we presume that there is always an identifier. The identifier slot
* will be removed later if there is none.
*/
// Number of explicitely specified properties.
final int numSpecified = properties.size();
// Number of synthetic properties that may be generated.
int numSynthetic;
int envelopeIndex = -1;
int geometryIndex = -1;
final AbstractIdentifiedType[] identifierTypes;
if (identifierCount == 0) {
numSynthetic = 0;
identifierTypes = null;
} else {
numSynthetic = 1;
identifierTypes = new AbstractIdentifiedType[identifierCount];
}
if (defaultGeometry != null) {
envelopeIndex = numSynthetic++;
if (!AttributeConvention.GEOMETRY_PROPERTY.equals(defaultGeometry.getName())) {
geometryIndex = numSynthetic++;
}
}
final AbstractIdentifiedType[] propertyTypes = new AbstractIdentifiedType[numSynthetic + numSpecified];
int propertyCursor = numSynthetic;
int identifierCursor = 0;
for (int i = 0; i < numSpecified; i++) {
final PropertyTypeBuilder builder = properties.get(i);
final AbstractIdentifiedType instance = builder.build();
propertyTypes[propertyCursor] = instance;
/*
* Collect the attributes to use as identifier components while we loop over all properties.
* A NullPointerException or an ArrayIndexOutOfBoundsException in this block would mean that
* identifierCount field has not been updated correctly by an addRole(AttributeRole) method.
*/
if (builder.isIdentifier()) {
identifierTypes[identifierCursor++] = instance;
}
/*
* If there is a default geometry, add a link named "sis:geometry" to that geometry.
* It may happen that the property created by the user is already named "sis:geometry",
* in which case we will avoid to duplicate the property.
*/
if (builder == defaultGeometry && geometryIndex >= 0) {
if (propertyTypes[geometryIndex] != null) {
/*
* Assuming that there is no bug in our implementation, this error could happen if the user
* has modified this FeatureTypeBuilder in another thread during this build() execution.
*/
throw new CorruptedObjectException();
}
propertyTypes[geometryIndex] = FeatureOperations.link(name(AttributeConvention.GEOMETRY_PROPERTY), instance);
}
propertyCursor++;
}
/*
* Create the "envelope" operation only after we created all other properties.
* Actually it is okay if the 'propertyTypes' array still contains null elements not needed for envelope calculation
* like "sis:identifier", since FeatureOperations.envelope(…) constructor ignores any property which is not for a value.
*/
if (envelopeIndex >= 0)
try {
propertyTypes[envelopeIndex] = FeatureOperations.envelope(name(AttributeConvention.ENVELOPE_PROPERTY), null, propertyTypes);
} catch (FactoryException e) {
throw new IllegalStateException(e);
}
/*
* If a synthetic identifier need to be created, create it now as the first property.
* It may happen that the user provided a single identifier component already named
* "sis:identifier", in which case we avoid to duplicate the property.
*/
if (identifierTypes != null) {
if (identifierCursor != identifierTypes.length) {
/*
* Assuming that there is no bug in our implementation, this error could happen if the user
* has modified this FeatureTypeBuilder in another thread during this build() execution.
*/
throw new CorruptedObjectException();
}
if (AttributeConvention.IDENTIFIER_PROPERTY.equals(identifierTypes[0].getName())) {
if (identifierCursor > 1) {
throw new IllegalStateException(Resources.format(Resources.Keys.PropertyAlreadyExists_2, getDisplayName(), AttributeConvention.IDENTIFIER_PROPERTY));
}
System.arraycopy(propertyTypes, 1, propertyTypes, 0, --propertyCursor);
} else {
propertyTypes[0] = FeatureOperations.compound(name(AttributeConvention.IDENTIFIER_PROPERTY), idDelimiter, idPrefix, idSuffix, identifierTypes);
}
}
feature = new DefaultFeatureType(identification(), isAbstract(), superTypes.toArray(new DefaultFeatureType[superTypes.size()]), ArraysExt.resize(propertyTypes, propertyCursor));
}
return feature;
}
Aggregations