Skip to content

Commit e642a12

Browse files
committed
Add wrappers for factories and register them in META-INF/services.
A side-effect of this work is the addition of `proj4j(…)` methods as the reverse of `geoapi(…)` methods.
1 parent 6651f74 commit e642a12

22 files changed

+1734
-15
lines changed

geoapi/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<links>
6565
<link>https://www.geoapi.org/3.0/javadoc/</link>
6666
</links>
67+
<excludePackageNames>org.locationtech.proj4j.geoapi.spi</excludePackageNames>
6768
</configuration>
6869
</plugin>
6970
</plugins>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright 2025, PROJ4J contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.locationtech.proj4j.geoapi;
17+
18+
import java.io.Serializable;
19+
import java.util.Set;
20+
import org.locationtech.proj4j.CRSFactory;
21+
import org.locationtech.proj4j.Proj4jException;
22+
import org.locationtech.proj4j.UnknownAuthorityCodeException;
23+
import org.opengis.metadata.citation.Citation;
24+
import org.opengis.referencing.IdentifiedObject;
25+
import org.opengis.referencing.NoSuchAuthorityCodeException;
26+
import org.opengis.referencing.crs.*;
27+
import org.opengis.util.FactoryException;
28+
import org.opengis.util.InternationalString;
29+
30+
31+
/**
32+
* Wraps a PROJ4J implementation behind the equivalent GeoAPI interface.
33+
*
34+
* @author Martin Desruisseaux (Geomatys)
35+
*/
36+
@SuppressWarnings("serial")
37+
final class AuthorityFactoryWrapper extends Wrapper implements CRSAuthorityFactory, Serializable {
38+
/**
39+
* The wrapped PROJ4 implementation.
40+
*/
41+
final CRSFactory impl;
42+
43+
/**
44+
* Creates a new wrapper for the given PROJ4J implementation.
45+
*/
46+
private AuthorityFactoryWrapper(final CRSFactory impl) {
47+
this.impl = impl;
48+
}
49+
50+
/**
51+
* Wraps the given implementation.
52+
*
53+
* @param impl the implementation to wrap, or {@code null}
54+
* @return the wrapper, or {@code null} if the given implementation was null
55+
*/
56+
static AuthorityFactoryWrapper wrap(final CRSFactory impl) {
57+
return (impl != null) ? new AuthorityFactoryWrapper(impl) : null;
58+
}
59+
60+
/**
61+
* {@return the PROJ4J backing implementation}.
62+
*/
63+
@Override
64+
Object implementation() {
65+
return impl;
66+
}
67+
68+
/**
69+
* {@return the factory name}.
70+
*/
71+
@Override
72+
public String getCode() {
73+
return "PROJ4J";
74+
}
75+
76+
/**
77+
* {@return an identification of the softwware that provides the CRS definitions}.
78+
* This is not the authority (EPSG, ESRI, <i>etc</i>).
79+
*/
80+
@Override
81+
public Citation getVendor() {
82+
return SimpleCitation.PROJ4J;
83+
}
84+
85+
/**
86+
* Returns the name of the CRS for the given code. Usually, this method is for fetching the name without the
87+
* cost of creating the full <abbr>CRS</abbr>. However, this implementation is inefficient in this regard.
88+
*/
89+
@Override
90+
public InternationalString getDescriptionText(String code) throws FactoryException {
91+
return LocalizedString.wrap(createCoordinateReferenceSystem(code).getName().getCode());
92+
}
93+
94+
/**
95+
* Generic method defined in parent interface.
96+
*/
97+
@Override
98+
public IdentifiedObject createObject(String code) throws FactoryException {
99+
return createCoordinateReferenceSystem(code);
100+
}
101+
102+
/**
103+
* Creates a CRS from a code in the {@code "AUTHORITY:CODE"} syntax.
104+
* If the authority is unspecified, then {@code "EPSG"} is assumed.
105+
*
106+
* @param code the authority (optional) and code of the CRS to create
107+
* @return the CRS for the given code
108+
* @throws FactoryException if the CRS cannot be created
109+
*/
110+
@Override
111+
public CoordinateReferenceSystem createCoordinateReferenceSystem(String code) throws FactoryException {
112+
try {
113+
return AbstractCRS.wrap(impl.createFromName(code), false);
114+
} catch (UnknownAuthorityCodeException e) {
115+
final int s = code.indexOf(':');
116+
throw (NoSuchAuthorityCodeException) new NoSuchAuthorityCodeException(
117+
"No registered CRS for \"" + code + "\".",
118+
(s >= 0) ? code.substring(0, s).trim() : null,
119+
(s >= 0) ? code.substring(s).trim() : code, code).initCause(e);
120+
} catch (Proj4jException e) {
121+
throw new FactoryException("Cannot create a CRS for \"" + code + "\".", e);
122+
}
123+
}
124+
125+
/**
126+
* Creates the CRS from the specified code and cast to a geographic CRS.
127+
*
128+
* @param code the authority (optional) and code of the CRS to create
129+
* @return the CRS for the given code
130+
* @throws FactoryException if the CRS cannot be created or is not geographic
131+
*/
132+
@Override
133+
public GeographicCRS createGeographicCRS(String code) throws FactoryException {
134+
try {
135+
return (GeographicCRS) createCoordinateReferenceSystem(code);
136+
} catch (ClassCastException e) {
137+
throw new FactoryException("The CRS identified by \"" + code + "\" is not geographic.", e);
138+
}
139+
}
140+
141+
/**
142+
* Creates the CRS from the specified code and cast to a projected CRS.
143+
*
144+
* @param code the authority (optional) and code of the CRS to create
145+
* @return the CRS for the given code
146+
* @throws FactoryException if the CRS cannot be created or is not projected
147+
*/
148+
@Override
149+
public ProjectedCRS createProjectedCRS(String code) throws FactoryException {
150+
try {
151+
return (ProjectedCRS) createCoordinateReferenceSystem(code);
152+
} catch (ClassCastException e) {
153+
throw new FactoryException("The CRS identified by \"" + code + "\" is not projected.", e);
154+
}
155+
}
156+
157+
@Override
158+
public GeocentricCRS createGeocentricCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
159+
throw new FactoryException("Not implemented.");
160+
}
161+
162+
@Override
163+
public VerticalCRS createVerticalCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
164+
throw new FactoryException("Not implemented.");
165+
}
166+
167+
@Override
168+
public TemporalCRS createTemporalCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
169+
throw new FactoryException("Not implemented.");
170+
}
171+
172+
@Override
173+
public EngineeringCRS createEngineeringCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
174+
throw new FactoryException("Not implemented.");
175+
}
176+
177+
@Override
178+
public ImageCRS createImageCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
179+
throw new FactoryException("Not implemented.");
180+
}
181+
182+
@Override
183+
public DerivedCRS createDerivedCRS(String code) throws NoSuchAuthorityCodeException, FactoryException {
184+
throw new FactoryException("Not implemented.");
185+
}
186+
187+
@Override
188+
public CompoundCRS createCompoundCRS(String code) throws FactoryException {
189+
throw new FactoryException("Not implemented.");
190+
}
191+
192+
@Override
193+
public Set<String> getAuthorityCodes(Class<? extends IdentifiedObject> type) throws FactoryException {
194+
throw new FactoryException("Not implemented.");
195+
}
196+
}

geoapi/src/main/java/org/locationtech/proj4j/geoapi/DatumWrapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ final class DatumWrapper extends Wrapper implements GeodeticDatum, Serializable
3636
/**
3737
* The wrapped PROJ4 implementation.
3838
*/
39-
private final org.locationtech.proj4j.datum.Datum impl;
39+
final org.locationtech.proj4j.datum.Datum impl;
4040

4141
/**
4242
* The prime meridian, or {@code null} for Greenwich

geoapi/src/main/java/org/locationtech/proj4j/geoapi/EllipsoidWrapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ final class EllipsoidWrapper extends Wrapper implements Ellipsoid, Serializable
3333
/**
3434
* The wrapped PROJ4 implementation.
3535
*/
36-
private final org.locationtech.proj4j.datum.Ellipsoid impl;
36+
final org.locationtech.proj4j.datum.Ellipsoid impl;
3737

3838
/**
3939
* Creates a new wrapper for the given PROJ4J implementation.

0 commit comments

Comments
 (0)