powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Java [игнор отключен] [закрыт для гостей] / SOLID & немного Spring'a
8 сообщений из 8, страница 1 из 1
SOLID & немного Spring'a
    #40118297
bobo96
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте, решал небольшую задачку чисто из спортивного интереса и залип на одном моменте. Все работает, но один кусок кода уж очень костыльный, а как исправить не знаю :(
Суть задачки в чем: дается линк, там массив json типа


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
[
    {
        "id": 1,
        "sourceDataUrl": "http://www.mocky.io/v2/5c51b230340000094f129f5d",
        "tokenDataUrl": "http://www.mocky.io/v2/5c51b5b6340000554e129f7b?mocky-delay=1s"
    },
    {
        "id": 20,
        "sourceDataUrl": "http://www.mocky.io/v2/5c51b2e6340000a24a129f5f?mocky-delay=100ms",
        "tokenDataUrl": "http://www.mocky.io/v2/5c51b5ed340000554e129f7e"
    },
    {
        "id": 3,
        "sourceDataUrl": "http://www.mocky.io/v2/5c51b4b1340000074f129f6c",
        "tokenDataUrl": "http://www.mocky.io/v2/5c51b600340000514f129f7f?mocky-delay=2s"
    },
    {
        "id": 2,
        "sourceDataUrl": "http://www.mocky.io/v2/5c51b5023400002f4f129f70",
        "tokenDataUrl": "http://www.mocky.io/v2/5c51b623340000404f129f82"
    }
]



Далее по линкам в каждом объекте еще один объект, их надо вытащить и поставить на место этого линка, то-есть вот это
Код: xml
1.
2.
3.
4.
5.
{
        "id": 1,
        "sourceDataUrl": "http://www.mocky.io/v2/5c51b230340000094f129f5d",
        "tokenDataUrl": "http://www.mocky.io/v2/5c51b5b6340000554e129f7b?mocky-delay=1s"
    }


нужно преобразовать в это:
Код: xml
1.
2.
3.
4.
5.
6.
7.
{
"id": 1,
"urlType": "LIVE",
"videoUrl": "rtsp://127.0.0.1/1",
"value": "fa4b588e-249b-11e9-ab14-d663bd873d93",
"ttl": 120
}



Контроллер:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
@RestController
@RequestMapping("/")
@AllArgsConstructor
public class CamController {

  private final CamService camService;

  @GetMapping("/cam")
  public ResponseEntity getAllCams() {
    List<ResponseModel> list;
    try {
      list = camService.dataProccess();
    } catch (IOException e) {
      e.printStackTrace();
      return ResponseEntity.badRequest().body("Query failed: " + e.getMessage());
    }
    return ResponseEntity.ok(list);
  }
}




Сервис:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
@Service
@AllArgsConstructor
public class CamService {

  @Value("${ru.korshun.target}")
  private final String url;

  private final AsyncHandler asyncHandler;

  public List<ResponseModel> dataProccess() throws IOException {

    List<CompletableFuture<ResponseModel>> futures = new ArrayList<>();
    String inputArray = asyncHandler.getStringFromUrl(url).orElse("[]");
    JSONArray json = new JSONArray(inputArray);

    IntStream
            .range(0, json.length())
            .mapToObj(i -> new Gson().fromJson(json.get(i).toString(), UrlModel.class))
            .forEach(i -> {
              try {
                futures.add(asyncHandler.getResult(i.getId(), i.getSourceDataUrl(), i.getTokenDataUrl()));
              } catch (IOException e) {
                e.printStackTrace();
              }
            });

    return futures.stream().map(CompletableFuture::join).collect(Collectors.toList());
  }

}



Вспомогательный класс (с костылем):
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
@Component
public class AsyncHandler {

  @Async
  public <T> CompletableFuture<T> getDataFromUrl(String url, Class<T> type) throws IOException {

    String inputJson = getStringFromUrl(url).orElse("");
    T tokenData = new Gson().fromJson(inputJson, type);

    return new AsyncResult<>(tokenData).completable();
  }

  @Async
  public CompletableFuture<ResponseModel> getResult(int id, String sourceDataUrl, String tokenDataUrl)
          throws IOException {

    CompletableFuture<SourceDataModel> sourceData =
            getDataFromUrl(sourceDataUrl, SourceDataModel.class);
    CompletableFuture<TokenDataModel> tokenData =
            getDataFromUrl(tokenDataUrl, TokenDataModel.class);

    ResponseModel responseModel = new ResponseModel();
    responseModel.setId(id);

    Stream.of(sourceData, tokenData).map(CompletableFuture::join).forEach(i -> {
      
      // как это обыграть по-другому ? Ибо второму принципу SOLID оно не соответствует от слова совсем))
      if (i instanceof SourceDataModel) {
        responseModel.setType(((SourceDataModel) i).getUrlType());
        responseModel.setUrl(((SourceDataModel) i).getVideoUrl());
      } else if (i instanceof TokenDataModel) {
        responseModel.setValue(((TokenDataModel) i).getValue());
        responseModel.setTtl(((TokenDataModel) i).getTtl());
      }
    });

    return new AsyncResult<>(responseModel).completable();
  }


  public Optional<String> getStringFromUrl(String url) throws IOException {
    return Optional.of(IOUtils.toString(new URL(url), StandardCharsets.UTF_8));
  }

}



Я не прошу прям кода, просьба хотя бы на словах объяснить, как эту логику с помощью абстракций реализовать)
Спасибо!
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118316
Фотография Valentin Kolesnikov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bobo96,

Можете воспользоваться библиотекой из соседней ветки .

Такое решение:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
    public void sqlru3() {
        String json = "[\n" +
                "    {\n" +
                "        \"id\": 1,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b230340000094f129f5d\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b5b6340000554e129f7b?mocky-delay=1s\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 20,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b2e6340000a24a129f5f?mocky-delay=100ms\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b5ed340000554e129f7e\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 3,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b4b1340000074f129f6c\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b600340000514f129f7f?mocky-delay=2s\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 2,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b5023400002f4f129f70\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b623340000404f129f82\"\n" +
                "    }\n" +
                "]";
        List<Map<String, Object>> objects = U.fromJson(json);
        String result = U.toJson(objects.stream().map(item -> {
                    Map<String, Object> sourceData = (Map<String, Object>) U.fetch((String) item.get("sourceDataUrl")).json();
                    Map<String, Object> tokenData = (Map<String, Object>) U.fetch((String) item.get("tokenDataUrl")).json();
                    U.Builder builder = U.objectBuilder();
                    sourceData.forEach(builder::add);
                    tokenData.forEach(builder::add);
                    return builder.build();
                }
        ).collect(Collectors.toList()));
        System.out.println(result);
    }



Результат:
Код: javascript
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
[
  {
    "urlType": "LIVE",
    "videoUrl": "rtsp://127.0.0.1/1",
    "value": "fa4b588e-249b-11e9-ab14-d663bd873d93",
    "ttl": 120
  },
  {
    "urlType": "ARCHIVE",
    "videoUrl": "rtsp://127.0.0.1/2",
    "value": "fa4b5b22-249b-11e9-ab14-d663bd873d93",
    "ttl": 60
  },
  {
    "urlType": "ARCHIVE",
    "videoUrl": "rtsp://127.0.0.1/3",
    "value": "fa4b5d52-249b-11e9-ab14-d663bd873d93",
    "ttl": 120
  },
  {
    "urlType": "LIVE",
    "videoUrl": "rtsp://127.0.0.1/20",
    "value": "fa4b5f64-249b-11e9-ab14-d663bd873d93",
    "ttl": 180
  }
]
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118318
Фотография Valentin Kolesnikov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В новой версии библиотеки можно будет не добавлять приведение типов.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
    public void sqlru3() {
        String json = "[\n" +
                "    {\n" +
                "        \"id\": 1,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b230340000094f129f5d\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b5b6340000554e129f7b?mocky-delay=1s\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 20,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b2e6340000a24a129f5f?mocky-delay=100ms\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b5ed340000554e129f7e\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 3,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b4b1340000074f129f6c\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b600340000514f129f7f?mocky-delay=2s\"\n" +
                "    },\n" +
                "    {\n" +
                "        \"id\": 2,\n" +
                "        \"sourceDataUrl\": \"http://www.mocky.io/v2/5c51b5023400002f4f129f70\",\n" +
                "        \"tokenDataUrl\": \"http://www.mocky.io/v2/5c51b623340000404f129f82\"\n" +
                "    }\n" +
                "]";
        List<Map<String, Object>> objects = U.fromJson(json);
        String result = U.of(objects).map(item ->
                    U.objectBuilder()
                            .addMap(U.fetch(U.get(item, "sourceDataUrl")).jsonMap())
                            .addMap(U.fetch(U.get(item, "tokenDataUrl")).jsonMap())
                            .build()
        ).toJson().item();
        System.out.println(result);
    }
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118319
Фотография Valentin Kolesnikov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для списка объектов такой код:

Код: java
1.
2.
3.
4.
5.
6.
7.
        List<Map<String, Object>> objects = U.fromJson(json);
        List<Map<String, Object>> result = U.map(objects, item ->
                U.objectBuilder()
                        .addMap(U.fetch(U.get(item, "sourceDataUrl")).jsonMap())
                        .addMap(U.fetch(U.get(item, "tokenDataUrl")).jsonMap())
                        .build()
        );
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118401
SpringMan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
По вопросу: для комбинации CompletableFuture есть к примеру метод CompletableFuture#thenCombine . Да и зачем две штуки CompleteableFuture запихивать в Stream и бегать по ним циклом?
Не по вопросу:
- Gson может сразу массив парсить - зачем JSONArray тащить
- Из константы можно получить CompletableFuture из CompletableFuture#completedFuture - зачем AsyncResult тащить?
- Если используется vertx, то у него есть http client, который может сдлеать запрос асинхронно и не нужен будет @Async
- Вызов метода с @Async не будет выполнятся асинхронно , при вызове из того же класса (скорее всего тут такой же кейс как по ссылке)
- Вполне можно подумать над тем, чтобы возвращать CompletableFuture из контроллера без промежуточных join вообще. join блочит поток, и если он есть в коде, то можно выстрелить легко ошибиться и сделать что-то не то. Поэтому от него лучше уходить максимально
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118457
bobo96
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем огромное спасибо за советы.
Один вопрос:

SpringMan

- Вполне можно подумать над тем, чтобы возвращать CompletableFuture из контроллера без промежуточных join вообще. join блочит поток, и если он есть в коде, то можно выстрелить легко ошибиться и сделать что-то не то. Поэтому от него лучше уходить максимально


Вот тут не понял, как такое реализовывать..
К примеру запустили мы 5 потоков, каким способом отследить все и вернуть результат только когда все потоки выполнились ?
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118476
SpringMan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
bobo96

Вот тут не понял, как такое реализовывать..
К примеру запустили мы 5 потоков, каким способом отследить все и вернуть результат только когда все потоки выполнились ?


Есть два метода:
CompletableFuture#thenCombine - может объединить результат нескольких CompletableFuture в одну CompletableFuture
CompletableFuture#thenCompose - может создать новую future после того, когда будет получен результат текущей

Псевдокод:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CompletableFuture finalResult = 
getDataFromUrlType1(initialUrl).thenCompose(initialUrlResult -> {
    CompletableFuture future1 = getDataFromUrlType2(firstUrlResult.url1);
    CompletableFuture future2 = getDataFromUrlType2(firstUrlResult.url2);
    
    return CompletableFuture.completedFuture(new ResponseData())
                            .thenCombine(future1, (responseData, future1Response) -> responseData.setUrl1Result(future1Response))
                            .thenCombine(future2, (responseData, future2Response) -> responseData.setUrl2Result(future2Response));
                           
});


Код само собой я не компилировал. Внутри thenCompose рождаются две future, а их результат объединяется через thenCombine. Мой пример короче чем нужно, но суть думаю ясна
...
Рейтинг: 0 / 0
SOLID & немного Spring'a
    #40118489
bobo96
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо!
Выглядит страшно, но буду вникать)
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / SOLID & немного Spring'a
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]