@@ -306,7 +306,10 @@ public B readTimeout(int readTimeout) {
306306 protected ServiceOptions (Class <? extends ServiceFactory <ServiceT , OptionsT >> serviceFactoryClass ,
307307 Class <? extends ServiceRpcFactory <ServiceRpcT , OptionsT >> rpcFactoryClass ,
308308 Builder <ServiceT , ServiceRpcT , OptionsT , ?> builder ) {
309- projectId = checkNotNull (builder .projectId != null ? builder .projectId : defaultProject ());
309+ projectId = builder .projectId != null ? builder .projectId : defaultProject ();
310+ if (projectIdRequired ()) {
311+ checkNotNull (projectId );
312+ }
310313 host = firstNonNull (builder .host , defaultHost ());
311314 httpTransportFactory = firstNonNull (builder .httpTransportFactory ,
312315 getFromServiceLoader (HttpTransportFactory .class , DefaultHttpTransportFactory .INSTANCE ));
@@ -325,6 +328,16 @@ protected ServiceOptions(Class<? extends ServiceFactory<ServiceT, OptionsT>> ser
325328 clock = firstNonNull (builder .clock , Clock .defaultClock ());
326329 }
327330
331+ /**
332+ * Returns whether a service requires a project ID. This method may be overridden in
333+ * service-specific Options objects.
334+ *
335+ * @return true if a project ID is required to use the service, false if not.
336+ */
337+ public boolean projectIdRequired () {
338+ return true ;
339+ }
340+
328341 private static AuthCredentials defaultAuthCredentials () {
329342 // Consider App Engine. This will not be needed once issue #21 is fixed.
330343 if (appEngineAppId () != null ) {
@@ -462,6 +475,8 @@ public ServiceRpcT rpc() {
462475
463476 /**
464477 * Returns the project id.
478+ *
479+ * Return value can be null (for services that don't require a project id).
465480 */
466481 public String projectId () {
467482 return projectId ;
0 commit comments