如果單一的 API 特別複雜,您可能要從多個 Java 類別實作 API。如要使不同的類別成為相同 API 的一部分,您必須:
- 在每個類別的
@Api
註解中提供相同的name
和version
字串。 - 在
web.xml
中透過逗號分隔清單的形式新增類別 API。
舉例來說,下列兩個類別都屬於 tictactoe
API 的一部分:
@Api(name = "tictactoe", version = "v1")
class TicTacToeA { … }
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
API 設定是透過 @Api
註解屬性指定。但是對於同一個 API 的多個類別,@Api
需求則會擴充,而不僅在 @Api
註解中為每個類別提供相同的 name
和 version
字串。實際上,如果在類別 @Api
屬性中指定的 API 設定出現「任何」差異,則後端 API 將無法運作。多重類別 API 中各類別的 @Api
屬性如果有任何差異,都會導致 API 設定變得「模稜兩可」,因而無法在 App Engine 適用的 Cloud Endpoints Frameworks 內運作。
您可以透過下列幾種方式建立明確的多重類別 API:
- 以手動方式確認單一 API 中所有類別都有完全相同的
@Api
註解屬性。 - 透過 Java 繼承使用註解繼承。在這個繼承中,單一 API 中的所有類別都會從一般以
@Api
註解的基本類別中,繼承相同的 API 設定。 - 透過
@ApiReference
註解,將註解繼承用於單一 API 中的所有類別,以參照一般@Api
註解類別中相同的 API 設定。
針對可能依類別而異的屬性使用 @ApiClass
如要使用這項功能,您必須匯入以下內容:
import com.google.api.server.spi.config.ApiClass;
雖然 @Api
註解中的所有屬性都必須與 API 內的所有類別相符,但您還可以透過 @ApiClass
註解,提供在各類別間不需要完全相同的屬性。例如:
// API methods implemented in this class allow only "clientIdA".
@Api(name = "tictactoe", version = "v1")
@ApiClass(clientIds = { "clientIdA" })
class TicTacToeA { … }
// API methods implemented in this class provide unauthenticated access.
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
其中 TicTacToeA
會使用用戶端 ID 許可清單 (其中包含允許的用戶端 ID) 來限制存取權,而 TicTacToeB
則不會限制存取權。
由 @ApiClass
註解提供的所有屬性在 @Api
註解中都有相等的屬性。請注意,@Api
相等屬性為整個 API 適用的預設值。如果在 @Api
中指定的同一屬性為整個 API 適用的預設值,則類別特定的 @ApiClass
屬性會覆寫整個 API 適用的預設值。
下列範例說明類別特定 @ApiClass
相等值覆寫 @Api
屬性的情況:
// For this class "boards" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "boards")
class TicTacToeBoards { … }
// For this class "scores" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "scores")
class TicTacToeScores { … }
// For this class, the API-wide default "games" is used as the resource.
@Api(name = "tictactoe", version = "v1", resource = "games")
class TicTacToeGames { … }
註解繼承
@Api
和 @ApiClass
註解屬性可以從其他類別繼承,個別屬性則能透過 Java 繼承或 @ApiReference
繼承加以覆寫
使用 Java 繼承
某個類別如果擴充其他含 @Api
或 @ApiClass
註解的類別,其行為就像使用相同屬性進行註解一樣。例如:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA and TicTacToeB both behave as if they have the same @Api annotation as
// TicTacToeBase
class TicTacToeA extends TicTacToeBase { … }
class TicTacToeB extends TicTacToeBase { … }
註解只會透過 Java 子類別繼承,而不是透過介面實作。例如:
@Api(name = "tictactoe", version = "v1")
interface TicTacToeBase { … }
// Does *not* behave as if annotated.
class TicTacToeA implements TicTacToeBase { … }
因此,系統「不支援」任何類型的架構註解多重繼承。
繼承也適用於 @ApiClass
:
@ApiClass(resource = "boards")
class BoardsBase { … }
// TicTacToeBoards behaves as if annotated with the @ApiClass from BoardsBase.
// Thus, the "resource" property will be "boards".
@Api(name = "tictactoe", version = "v1", resource = "scores")
class TicTacToeBoards extends BoardsBase { … }
其中 TicTacToeBoards
會從 BoardsBase
繼承 resource
屬性值 boards
,進而覆寫其 @Api
註解中的 resource
屬性設定 (scores
)。請記得,如有任何類別在 @Api
註解中指定資源屬性,則所有類別都必須在 @Api
註解中指定相同設定;此繼承技巧可讓您覆寫這個 @Api
屬性。
使用 @ApiReference
繼承
如要使用這項功能,您必須匯入以下內容:
import com.google.api.server.spi.config.ApiReference;
@ApiReference
註解提供了另一種指定註解繼承的方式。某個類別如果藉由 @ApiReference
來指定其他含 @Api
或 @ApiClass
註解的類別,其行為就像使用相同屬性進行註解一樣。例如:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA behaves as if it has the same @Api annotation as TicTacToeBase
@ApiReference(TicTacToeBase.class)
class TicTacToeA { … }
如果同時使用 Java 繼承和 @ApiReference
,註解只會透過 @ApiReference
註解繼承。類別上透過 Java 繼承所繼承的 @Api
和 @ApiClass
註解都會遭到忽略。例如:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBaseA { … }
@Api(name = "tictactoe", version = "v2")
class TicTacToeBaseB { … }
// TicTacToe will behave as if annotated the same as TicTacToeBaseA, not TicTacToeBaseB.
// The value of the "version" property will be "v1".
@ApiReference(TicTacToeBaseA.class)
class TicTacToe extends TicTacToeBaseB { … }
覆寫繼承的設定
無論您是使用 Java 繼承還是 @ApiReference
來繼承設定,都能使用新的 @Api
或 @ApiClass
註解覆寫繼承的設定。系統只會覆寫新註解中指定的設定屬性,未指定的屬性仍保留繼承值。例如:
@Api(name = "tictactoe", version = "v2")
class TicTacToe { … }
// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@Api(name = "checkers")
class Checkers extends TicTacToe { … }
覆寫繼承也適用於 @ApiClass
:
@Api(name = "tictactoe", version = "v1")
@ApiClass(resource = "boards", clientIds = { "c1" })
class Boards { … }
// Scores will behave as if annotated with resource = "scores" and clientIds = { "c1" }
@ApiClass(resource = "scores")
class Scores { … }
在透過 @ApiReference
繼承時也適用覆寫:
@Api(name = "tictactoe", version = "v2")
class TicTacToe { … }
// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@ApiReference(TicTacToe.class)
@Api(name = "checkers")
class Checkers { … }
繼承 @ApiMethod
註解
@ApiMethod
註解可以從已覆寫的方法繼承。例如:
class TicTacToeBase {
@ApiMethod(httpMethod = "POST")
public Game setGame(Game game) { … }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
// setGame behaves as if annotated with the @ApiMethod from TicTacToeBase.setGame.
// Thus the "httpMethod" property will be "POST".
@Override
public Game setGame(Game game) { … }
}
與 @Api
和 @ApiClass
註解繼承相似,如果互相覆寫的多個方法都有 @ApiMethod
註解,則可以覆寫個別屬性。例如:
class TicTacToeBase {
@ApiMethod(httpMethod = "POST", clientIds = { "c1" })
public Game setGame(Game game) { … }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
// setGame behaves as if annotated with httpMethod = "GET" and clientIds = { "c1"}.
@ApiMethod(httpMethod = "GET")
@Override
public Game setGame(Game game) { … }
}
由於沒有 @ApiReference
註解或相等的方法,因此一律會透過 Java 繼承來繼承 @ApiMethod
,而非透過 @ApiReference
。
繼承和優先順序規則
下表概要列出前面討論的繼承規則和優先順序。
註解/繼承 | 規則 |
---|---|
@Api |
所有類別必須相同。 |
@ApiClass |
為類別指定以覆寫 @Api 屬性。 |
Java 繼承 | 類別繼承基本類別的 @Api 和 @ApiClass 。 |
@ApiReference |
類別繼承參照類別的 @Api 和 @ApiClass 。 |
在從基本類別繼承的類別 (Java) 上使用 @ApiReference |
類別繼承參照類別的 @Api 和 @ApiClass ,而「不是」從基本類別繼承。 |
註解繼承的常見用途
以下為繼承的常見用途範例:
用於 API 版本管理:
@Api(name = "tictactoe", version = "v1")
class TicTacToeV1 { … }
@Api(version = "v2")
class TicTacToeV2 extends TicTacToeV1 { … }
用於多重類別 API:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {}
@ApiClass(resource = "boards")
class TicTacToeBoards extends TicTacToeBase { … }
@ApiClass(resource = "scores")
class TicTacToeScores extends TicTacToeBase { … }
用於測試相同 API 的不同版本:
@Api(name = "tictactoe", version = "v1")
class TicTacToe {
protected Foo someMethod() {
// Do something real;
}
public Foo getFoo() { … }
}
@Api(version="v1test")
class TicTacToeTest extends TicTacToe {
protected Foo someMethod() {
// Stub out real action;
}
}
其中 someMethod
可能會傳回預先建立的回應、避免具副作用的呼叫、略過網路或資料儲存庫要求等等。
新增類別到 web.xml
將類別加註之後,您必須將類別新增到 web.xml
檔案中。以下範例說明單一類別:
如何新增多個類別:
將
<param-value>com.example.skeleton.MyApi</param-value>
改成您自己的 API 類別名稱。在相同
<param-value>
欄位中,以逗號分隔方式新增每個類別,如下所示:<param-value>com.example-company.example-api.Hello,com.example-company.example-api.Goodbye</param-value>