Я пытаюсь свести к минимуму повторяющийся код для ряда обработчиков ресурсов JAX-RS, для каждого из которых требуется несколько одинаковых путей и параметров запроса. Базовый шаблон URL-адреса для каждого ресурса выглядит следующим образом:
/{id}/resourceName
и каждый ресурс имеет несколько подресурсов:
/{id}/resourceName/subresourceName
Таким образом, пути ресурса / подресурса (включая параметры запроса) могут выглядеть так:
/12345/foo/bar?xyz=0
/12345/foo/baz?xyz=0
/12345/quux/abc?xyz=0
/12345/quux/def?xyz=0
Общие части ресурсов foo
и quux
- это @PathParam ("id")
и @QueryParam ("xyz")
. Я мог реализовать классы ресурсов следующим образом:
// FooService.java
@Path("/{id}/foo")
public class FooService
{
@PathParam("id") String id;
@QueryParam("xyz") String xyz;
@GET @Path("bar")
public Response getBar() { /* snip */ }
@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
@Path("/{id}/quux")
public class QuxxService
{
@PathParam("id") String id;
@QueryParam("xyz") String xyz;
@GET @Path("abc")
public Response getAbc() { /* snip */ }
@GET @Path("def")
public Response getDef() { /* snip */ }
}
Мне удалось избежать повторения инъекции параметров в каждый метод get *
. 1 Это хорошее начало, но я бы хотел также избежать повторения в классах ресурсов. Подход, который работает с CDI (который мне также нужен), заключается в использовании абстрактного
базового класса, который FooService
и QuuxService
может расширять
:
// BaseService.java
public abstract class BaseService
{
// JAX-RS injected fields
@PathParam("id") protected String id;
@QueryParam("xyz") protected String xyz;
// CDI injected fields
@Inject protected SomeUtility util;
}
// FooService.java
@Path("/{id}/foo")
public class FooService extends BaseService
{
@GET @Path("bar")
public Response getBar() { /* snip */ }
@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
@Path("/{id}/quux")
public class QuxxService extends BaseService
{
@GET @Path("abc")
public Response getAbc() { /* snip */ }
@GET @Path("def")
public Response getDef() { /* snip */ }
}
Внутри методов get *
внедрение CDI (чудесным образом) работает правильно: поле util
не равно нулю. К сожалению, внедрение JAX-RS не работает; id
и xyz
равны null
в методах get *
FooService
и [1115613760] QuuxService] .
Учитывая, что CDI работает так, как я бы хотел, мне интересно, не удалось ли ввести @PathParam
s (и т. Д.) .) в подклассы - это ошибка или просто часть спецификации JAX-RS.
Другой подход, который я уже пробовал, - это использование BaseService
в качестве единой точки входа, которая делегирует FooService
] и QuuxService
по мере необходимости. В основном это описано в RESTful Java с JAX-RS с использованием локаторов подресурсов.
// BaseService.java
@Path("{id}")
public class BaseService
{
@PathParam("id") protected String id;
@QueryParam("xyz") protected String xyz;
@Inject protected SomeUtility util;
public BaseService () {} // default ctor for JAX-RS
// ctor for manual "injection"
public BaseService(String id, String xyz, SomeUtility util)
{
this.id = id;
this.xyz = xyz;
this.util = util;
}
@Path("foo")
public FooService foo()
{
return new FooService(id, xyz, util); // manual DI is ugly
}
@Path("quux")
public QuuxService quux()
{
return new QuuxService(id, xyz, util); // yep, still ugly
}
}
// FooService.java
public class FooService extends BaseService
{
public FooService(String id, String xyz, SomeUtility util)
{
super(id, xyz, util); // the manual DI ugliness continues
}
@GET @Path("bar")
public Response getBar() { /* snip */ }
@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
public class QuuzService extends BaseService
{
public FooService(String id, String xyz, SomeUtility util)
{
super(id, xyz, util); // the manual DI ugliness continues
}
@GET @Path("abc")
public Response getAbc() { /* snip */ }
@GET @Path("def")
public Response getDef() { /* snip */ }
}
Обратной стороной этого подхода является то, что ни внедрение CDI, ни внедрение JAX-RS не работают в классах подресурсов. Причина этого довольно очевидна 2 , но то, что это означает , заключается в том, что мне приходится вручную повторно вводить поля в конструктор подклассов, что беспорядочно, некрасиво и не так. Мне нелегко настроить дальнейшую инъекцию. Пример: скажем, я хотел @Inject
экземпляр в FooService
, но не QuuxService
. Поскольку я явно создаю экземпляры подклассов BaseService
, внедрение CDI не будет работать, поэтому уродство продолжается.
С небольшим указанием от @Tarlog , я думаю, что нашел ответ на один из моих вопросов,
Почему не не унаследованные поля, введенные JAX-RS?
В JSR-311 §3.6 :
Если подкласс или метод реализации имеет какие-либо аннотации JAX-RS, то все из аннотации суперкласса или метода интерфейса игнорируются.
Я уверен, что для этого решения есть реальная причина, но, к сожалению, этот факт работает против меня в данном конкретном случае использования. Меня все еще интересуют возможные обходные пути.
1 Предостережение при использовании инъекции на уровне поля состоит в том, что теперь я привязан к созданию экземпляров класса ресурсов для каждого запроса, но я могу с этим жить.
2 Потому что я
в игровой зоне случайным образом расположены связки звезд. Есть три типа звезд: большие звезды быстрее, меньшие звезды движутся медленнее.
Это выглядит так:
~ 10% времени все звезды появляются в «полосах»
Думаю, стоит упомянуть, что даже при том, что они в узких полосах; они не все в одном и том же положении. Это похоже на то, что он все еще генерирует случайное число - только крошечное.
Чтобы воспроизвести ошибку, я просто нажимаю «f5» в браузере. Практически всегда он работает, как ожидалось. Редко получаются полосы. Повторное нажатие «f5» решит проблему.
Без публикации гигантской стены кода; Я считаю, что это наиболее актуальный код. Похоже, в базовом классе наследуются все мои звезды. Он вызывается один раз, когда создается каждая звезда.
Protected Sub SetInitialPosition()
myElipse.Height = GetStarSize()
myElipse.Width = GetStarSize()
_location.X = GetRandom.Next(-1 * Settings.StarEdge, CType(GameCanvas.Width, Integer) + Settings.StarEdge)
_location.Y = GetRandom.Next(0, CType(GameCanvas.Height, Integer))
myElipse.Fill = New SolidColorBrush(GetStarColor)
End Sub
Я не вижу ничего плохого. GetRandom () возвращает одноэлементный класс Random, и я зависим от допустимости GameCanvas.Height и GameCanvas.Width, но опять же, .Width, похоже, работает именно так, как ожидалось.
Есть ли у кого-нибудь возможное объяснение такого поведения? Есть ли какие-то ошибки, на которые следует обратить внимание при генерации случайных чисел? Каждый раз, когда я просматриваю код, все в порядке, и игра работает должным образом.
Если это поможет, я могу опубликовать ссылку на игру.
( http://robdude.weebly.com/cci.html )
ИЗМЕНИТЬ №1:
Вот код из GetRandom ()
Protected Shared Function GetRandom() As Random
If _random Is Nothing Then _random = New Random()
Return _random
End Function
ИЗМЕНИТЬ №2: Я очень ценю все мысли / советы по этому поводу.