This file provides additional context for AI assistants working with this codebase.
Integration with Norwegian Matrikkel (cadastral register) SOAP API to download and store property data in PostgreSQL.
- Automatic SOAP Serialization: JAX-WS handles complex nested objects (MatrikkelBubbleId with snapshotVersion) without manual XML construction
- Type Safety: Compile-time checking prevents runtime errors
- Better Tooling: wsimport generates perfect client classes from WSDL
- Official Support: Matrikkel API documentation uses Java examples
- Dependency injection for clean architecture
- Spring Data JPA for database abstraction
- Excellent PostgreSQL integration
- Built-in transaction management
- Production-ready features (health checks, metrics)
- API supports up to 5000 objects per batch
- More efficient than offset-based pagination for large datasets
- Uses MatrikkelBubbleId as cursor for next batch
- Automatically stops when receiving fewer objects than requested
public class MatrikkelBubbleId {
private Long value; // Object ID
private SnapshotVersion version; // Temporal version
}SnapshotVersion snapshotVersion = new SnapshotVersion();
ZonedDateTime futureDate = ZonedDateTime.of(9999, 1, 1, 0, 0, 0, 0, ZoneId.of("Europe/Oslo"));
snapshotVersion.setTimestamp(futureDate);Why future date?
- Matrikkel API has temporal versioning
- Historical data requires special permissions
- Using far future date (9999-01-01) ensures we get current data
- This matches working PHP implementation
MatrikkelBubbleId cursor = null;
do {
List<Matrikkelenhet> batch = nedlastningService.findObjekterEtterId(
cursor, // null for first batch
"Matrikkelenhet", // Object type
"{\"kommunefilter\": [\"4601\"]}", // JSON filter
5000, // Max batch size
context // With snapshotVersion
);
// Process batch...
// Get last object's ID as cursor
cursor = batch.get(batch.size() - 1).getId();
// Stop if batch is smaller than requested (last batch)
if (batch.size() < 5000) break;
} while (true);matrikkel_matrikkelenheter- Property units (main table)matrikkel_eiere- Owners (1:many with matrikkelenheter)matrikkel_adresser- Addresses (1:many with matrikkelenheter)
Matrikkelenhet (1) ←→ (many) Eier
Matrikkelenhet (1) ←→ (many) Adresse
kommunenummer- Primary query filtergardsnummer, bruksnummer- Property identificationmatrikkelenhet_id- API object ID (unique)
@Service
@Transactional
public class MatrikkelenhetImportService {
public int importMatrikkelenheterForKommune(String kommunenummer) {
// 1. Fetch from API
List<ApiMatrikkelenhet> apiObjects =
nedlastningClient.findAllMatrikkelenheterForKommune(kommunenummer);
// 2. Map to entities
List<Matrikkelenhet> entities = apiObjects.stream()
.map(mapper::toEntity)
.collect(Collectors.toList());
// 3. Save (batch insert)
return repository.saveAll(entities).size();
}
}@Component
public class NedlastningClientWrapper {
private final NedlastningService nedlastningService; // Auto-configured
public List<Matrikkelenhet> findAllMatrikkelenheterForKommune(String kommunenummer) {
// Pagination loop
// Error handling
// Logging
}
}@Repository
public interface MatrikkelenhetRepository extends JpaRepository<Matrikkelenhet, Long> {
Optional<Matrikkelenhet> findByMatrikkelenhetId(Long matrikkelenhetId);
List<Matrikkelenhet> findByKommunenummer(String kommunenummer);
@Query("SELECT m FROM Matrikkelenhet m WHERE ...")
Optional<Matrikkelenhet> customQuery(...);
}# 1. Add WSDL file
cp ServiceXYZ.wsdl src/main/resources/wsdl/
# 2. Add execution block in pom.xml
<execution>
<id>wsimport-xyz</id>
<configuration>
<wsdlFiles><wsdlFile>ServiceXYZ.wsdl</wsdlFile></wsdlFiles>
<packageName>no.matrikkel.client.generated.xyz</packageName>
</configuration>
</execution>
# 3. Generate classes
mvn clean compile
# 4. Create wrapper
@Component
public class XyzClientWrapper {
private final XyzService xyzService;
// ...
}
# 5. Register bean
@Bean
public XyzService xyzService() throws Exception {
// ...
}# 1. Create entity class
@Entity
@Table(name = "matrikkel_xyz")
public class XyzEntity { ... }
# 2. Create repository
public interface XyzRepository extends JpaRepository<XyzEntity, Long> { ... }
# 3. Create Flyway migration
# V{version}__add_xyz_table.sql
# 4. Create service
@Service
public class XyzImportService { ... }// Unit test - Mock dependencies
@ExtendWith(MockitoExtension.class)
class ServiceTest {
@Mock private SoapClient client;
@Mock private Repository repository;
@InjectMocks private Service service;
@Test
void testLogic() { ... }
}
// Integration test - Real database
@SpringBootTest
@Testcontainers
class IntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = ...;
@Test
void testFullFlow() { ... }
}- Hibernate batch size: 100 (configured in application.yml)
- Use
saveAll()instead of multiplesave()calls - Consider
@Transactional(propagation = Propagation.REQUIRES_NEW)for large batches
spring.datasource.hikari:
maximum-pool-size: 10
minimum-idle: 2
connection-timeout: 30000- Don't load all objects into memory at once
- Process batches incrementally
- Consider streaming for very large datasets
- ✅ Use environment variables
- ✅ Use Spring Boot's encrypted properties
- ❌ Never commit credentials to git
- ❌ Never hardcode passwords in code
// Basic Auth via JAX-WS
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);INFO- Batch progress, import summariesDEBUG- API calls, SQL queries, detailed flowWARN- Recoverable errors, retriesERROR- Fatal errors, data corruption
- Objects imported per batch
- Total import time
- API response times
- Database insert performance
- Error rates
Solution: Set snapshotVersion to far future date (9999-01-01)
Solution: Check if batch.size() < maxBatchSize condition is correct
Solution: Process batches incrementally, don't accumulate all objects
Solution: Increase timeout in application.yml or implement retry logic
- PHP Implementation:
/opt/matrikkel/(reference for API behavior) - WSDL Documentation:
/opt/matrikkel/doc/wsdl/
# Build
mvn clean package
# Run with specific profile
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# Generate classes from WSDL only
mvn generate-sources
# Run specific test
mvn test -Dtest=MatrikkelenhetImportServiceTest
# Database migration
mvn flyway:migrate
mvn flyway:info
mvn flyway:clean # CAUTION: Drops all objects!
# Docker
docker-compose up -d postgres
docker-compose logs -f matrikkel-app4601 - Use for all testing/examples
- Test:
https://wsweb-test.matrikkel.no/matrikkel-ws-v1.0/ - Prod:
https://wsweb.matrikkel.no/matrikkel-ws-v1.0/
- Host: 10.0.2.15
- Port: 5435
- Database: matrikkel
- Schema: public
This context file should help AI assistants understand the project structure, patterns, and important implementation details when assisting with code generation and problem-solving.