Гость
Форумы / Java [игнор отключен] [закрыт для гостей] / SOLID & немного Spring'a / 8 сообщений из 8, страница 1 из 1
07.12.2021, 23:23
    #40118297
bobo96
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
Здравствуйте, решал небольшую задачку чисто из спортивного интереса и залип на одном моменте. Все работает, но один кусок кода уж очень костыльный, а как исправить не знаю :(
Суть задачки в чем: дается линк, там массив 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
08.12.2021, 04:55
    #40118316
Valentin Kolesnikov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
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
08.12.2021, 05:30
    #40118318
Valentin Kolesnikov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
В новой версии библиотеки можно будет не добавлять приведение типов.

Код: 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
08.12.2021, 05:38
    #40118319
Valentin Kolesnikov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
Для списка объектов такой код:

Код: 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
08.12.2021, 13:53
    #40118401
SpringMan
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
По вопросу: для комбинации CompletableFuture есть к примеру метод CompletableFuture#thenCombine . Да и зачем две штуки CompleteableFuture запихивать в Stream и бегать по ним циклом?
Не по вопросу:
- Gson может сразу массив парсить - зачем JSONArray тащить
- Из константы можно получить CompletableFuture из CompletableFuture#completedFuture - зачем AsyncResult тащить?
- Если используется vertx, то у него есть http client, который может сдлеать запрос асинхронно и не нужен будет @Async
- Вызов метода с @Async не будет выполнятся асинхронно , при вызове из того же класса (скорее всего тут такой же кейс как по ссылке)
- Вполне можно подумать над тем, чтобы возвращать CompletableFuture из контроллера без промежуточных join вообще. join блочит поток, и если он есть в коде, то можно выстрелить легко ошибиться и сделать что-то не то. Поэтому от него лучше уходить максимально
...
Рейтинг: 0 / 0
08.12.2021, 16:51
    #40118457
bobo96
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
Всем огромное спасибо за советы.
Один вопрос:

SpringMan

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


Вот тут не понял, как такое реализовывать..
К примеру запустили мы 5 потоков, каким способом отследить все и вернуть результат только когда все потоки выполнились ?
...
Рейтинг: 0 / 0
08.12.2021, 17:47
    #40118476
SpringMan
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
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
08.12.2021, 18:13
    #40118489
bobo96
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SOLID & немного Spring'a
Спасибо!
Выглядит страшно, но буду вникать)
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / SOLID & немного Spring'a / 8 сообщений из 8, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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