Se uma única API for particularmente complexa, é recomendável implementá-la a partir de várias classes Java. Para tornar diferentes classes parte da mesma API, tem de:
- Atribua a cada classe as mesmas strings
name
eversion
na respetiva anotação@Api
. - Adicione APIs de classe como uma
lista separada por vírgulas em
web.xml
.
Por exemplo, as duas classes seguintes fazem parte da API tictactoe
:
@Api(name = "tictactoe", version = "v1")
class TicTacToeA { … }
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
A configuração da API é especificada através das propriedades de anotação @Api
.
No entanto, para várias classes na mesma API, os requisitos de @Api
vão além de ter simplesmente as mesmas strings name
e version
na anotação @Api
para cada classe. Na verdade, a sua API de back-end não funciona se existirem diferenças nas configurações da API especificadas nas propriedades das classes @Api
. Qualquer diferença nas propriedades @Api
para classes num resultado da API de várias classes resulta numa configuração da API "ambígua", que não funciona nos frameworks do Cloud Endpoints para o App Engine.
Existem várias formas de criar uma API de várias classes não ambígua:
- Certifique-se manualmente de que todas as classes numa única API têm exatamente as mesmas propriedades de anotação
@Api
. - Use a herança de anotações através da
herança Java.
Nesta herança, todas as classes numa única API herdam a mesma configuração da API de uma classe base anotada com
@Api
. - Use a herança de anotações através da anotação
@ApiReference
em todas as classes numa única API para que façam referência à mesma configuração da API a partir de uma classe comum anotada com@Api
.
Usar @ApiClass
para propriedades que podem diferir entre classes
Para usar esta funcionalidade, precisa da seguinte importação:
import com.google.api.server.spi.config.ApiClass;
Embora todas as propriedades na anotação @Api
tenham de corresponder a todas as classes numa API, também pode usar a anotação @ApiClass
para fornecer propriedades que não têm de ser exatamente iguais entre as classes. Por exemplo:
// 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 { … }
em que TicTacToeA
limita o acesso através de uma lista de autorizações de IDs de clientes que contém o ID de cliente permitido e TicTacToeB
não limita o acesso.
Todas as propriedades fornecidas pela anotação @ApiClass
têm uma propriedade equivalente na anotação @Api
. Tenha em atenção que a propriedade equivalente @Api
funciona
como predefinição ao nível da API. Se existir uma predefinição ao nível da API para essa mesma propriedade, especificada em @Api
, a propriedade @ApiClass
específica da turma substitui a predefinição ao nível da API.
Os exemplos seguintes ilustram a substituição das propriedades @Api
pelos equivalentes @ApiClass
específicos da classe:
// 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 { … }
Herança de anotações
As propriedades de anotação @Api
e @ApiClass
podem ser herdadas de outras classes, e as propriedades individuais podem ser substituídas através da herança Java ou da herança @ApiReference
Usar a herança Java
Uma classe que estende outra classe com anotações @Api
ou @ApiClass
comporta-se como se tivesse anotações com as mesmas propriedades. Por exemplo:
@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 { … }
As anotações só são herdadas através da criação de subclasses Java e não através da implementação de interfaces. Por exemplo:
@Api(name = "tictactoe", version = "v1")
interface TicTacToeBase { … }
// Does *not* behave as if annotated.
class TicTacToeA implements TicTacToeBase { … }
Como tal, não existe suporte para qualquer tipo de herança múltipla de anotações de frameworks.
A herança também funciona para @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 { … }
onde TicTacToeBoards
herda o valor da propriedade resource
de boards
, substituindo assim a definição da propriedade resource
(scores
) na respetiva anotação @Api
.BoardsBase
Lembre-se de que, se alguma classe tiver especificado a propriedade
do recurso na anotação @Api
, todas as classes têm de especificar essa mesma
definição na anotação @Api
. Esta técnica de herança permite substituir
essa propriedade @Api
.
Usar a herança de @ApiReference
Para usar esta funcionalidade, precisa da seguinte importação:
import com.google.api.server.spi.config.ApiReference;
A anotação @ApiReference
oferece uma forma alternativa de especificar a herança de anotações. Uma classe que usa @ApiReference
para especificar outra classe com anotações @Api
ou @ApiClass
comporta-se como se tivesse anotações com as mesmas propriedades. Por exemplo:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA behaves as if it has the same @Api annotation as TicTacToeBase
@ApiReference(TicTacToeBase.class)
class TicTacToeA { … }
Se forem usados a herança Java e o @ApiReference
, as anotações são herdadas apenas através da anotação @ApiReference
. As anotações @Api
e @ApiClass
na classe herdada através da herança Java são ignoradas. Por
exemplo:
@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 { … }
Substituir a configuração herdada
Quer herde a configuração através da herança Java ou @ApiReference
, pode substituir a configuração herdada através de uma nova anotação @Api
ou @ApiClass
. Apenas as propriedades de configuração especificadas na nova anotação são substituídas. As propriedades não especificadas continuam a ser herdadas.
Por exemplo:
@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 { … }
A substituição da herança também funciona para @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 { … }
A substituição também funciona quando a herança é feita através de @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 { … }
Herdar anotações de @ApiMethod
A anotação @ApiMethod
pode ser herdada de métodos substituídos. Por
exemplo:
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) { … }
}
Tal como na herança de anotações @Api
e @ApiClass
, se vários métodos que se substituem mutuamente tiverem anotações @ApiMethod
, as propriedades individuais podem ser substituídas. Por exemplo:
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) { … }
}
Não existe uma anotação @ApiReference
nem um equivalente para métodos, pelo que @ApiMethod
é sempre herdado através da herança Java e não através de @ApiReference
.
Regras de herança e precedência
Para resumir a discussão anterior, a tabela seguinte mostra as regras de herança e a ordem de precedência.
Anotação/herança | Regra |
---|---|
@Api |
Tem de ser idêntico para todas as aulas. |
@ApiClass |
Especificado para uma classe para substituir as propriedades @Api . |
Herança Java | A classe herda @Api e @ApiClass da classe base. |
@ApiReference |
A classe herda @Api e @ApiClass da classe referenciada. |
Usar @ApiReference numa classe (Java) que herda de uma classe base |
A classe herda os atributos @Api e @ApiClass da classe referenciada, não da classe base. |
Exemplos de utilização comuns para a herança de anotações
Seguem-se exemplos de utilização típicos da herança:
Para o controlo de versões da API:
@Api(name = "tictactoe", version = "v1")
class TicTacToeV1 { … }
@Api(version = "v2")
class TicTacToeV2 extends TicTacToeV1 { … }
Para APIs de várias classes:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {}
@ApiClass(resource = "boards")
class TicTacToeBoards extends TicTacToeBase { … }
@ApiClass(resource = "scores")
class TicTacToeScores extends TicTacToeBase { … }
Para testar diferentes versões da mesma 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;
}
}
em que someMethod
pode devolver respostas predeterminadas, evitar chamadas com efeitos secundários, ignorar um pedido de rede ou de armazenamento de dados, entre outros.
Adicionar as turmas a web.xml
Depois de anotar as suas classes, tem de as adicionar ao ficheiro web.xml
. O exemplo seguinte mostra uma única classe:
Para adicionar várias classes:
Substitua
<param-value>com.example.skeleton.MyApi</param-value>
pelo nome da classe API.Adicione cada classe neste mesmo campo
<param-value>
separada por uma vírgula, por exemplo:<param-value>com.example-company.example-api.Hello,com.example-company.example-api.Goodbye</param-value>