<NME> MessageJsonReconstructionTest.java
<BEF> /*
 * Copyright 2018 LINE Corporation
 *
 * LINE Corporation licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.linecorp.bot.model.message;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;

import java.net.URI;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.linecorp.bot.model.message.flex.component.Text;
import com.linecorp.bot.model.message.flex.component.Text.TextWeight;
import com.linecorp.bot.model.message.flex.container.Bubble;
import com.linecorp.bot.model.message.flex.unit.FxFontSize;
import com.linecorp.bot.model.message.flex.unit.FxLayout;
import com.linecorp.bot.model.message.flex.unit.FxMarginSize;
import com.linecorp.bot.model.message.imagemap.ImagemapBaseSize;
import com.linecorp.bot.model.message.template.ButtonsTemplate;
import com.linecorp.bot.model.message.template.CarouselColumn;

import com.linecorp.bot.model.Broadcast;
import com.linecorp.bot.model.Multicast;
import com.linecorp.bot.model.Narrowcast;
import com.linecorp.bot.model.action.CameraAction;
import com.linecorp.bot.model.action.CameraRollAction;
import com.linecorp.bot.model.action.DatetimePickerAction;
import com.linecorp.bot.model.action.DatetimePickerAction.OfLocalDate;
import com.linecorp.bot.model.action.DatetimePickerAction.OfLocalDatetime;
import com.linecorp.bot.model.action.DatetimePickerAction.OfLocalTime;
import com.linecorp.bot.model.action.LocationAction;
import com.linecorp.bot.model.action.MessageAction;
import com.linecorp.bot.model.action.PostbackAction;
import com.linecorp.bot.model.action.URIAction;
import com.linecorp.bot.model.action.URIAction.AltUri;
import com.linecorp.bot.model.message.imagemap.ImagemapBaseSize;
import com.linecorp.bot.model.message.quickreply.QuickReply;
import com.linecorp.bot.model.message.quickreply.QuickReplyItem;
import com.linecorp.bot.model.message.template.ButtonsTemplate;
import com.linecorp.bot.model.message.template.CarouselColumn;
import com.linecorp.bot.model.message.template.CarouselTemplate;
import com.linecorp.bot.model.message.template.ConfirmTemplate;
import com.linecorp.bot.model.narrowcast.Filter;
import com.linecorp.bot.model.narrowcast.filter.AgeDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.AgeDemographicFilter.Age;
import com.linecorp.bot.model.narrowcast.filter.AppTypeDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.AppTypeDemographicFilter.AppType;
import com.linecorp.bot.model.narrowcast.filter.AreaDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.AreaDemographicFilter.AreaCode;
import com.linecorp.bot.model.narrowcast.filter.GenderDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.GenderDemographicFilter.Gender;
import com.linecorp.bot.model.narrowcast.filter.OperatorDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.SubscriptionPeriodDemographicFilter;
import com.linecorp.bot.model.narrowcast.filter.SubscriptionPeriodDemographicFilter.SubscriptionPeriod;
import com.linecorp.bot.model.testutil.TestUtil;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * Message object reconstruction test.
 *
 * <p>This is not a part of SDK SPEC but please check it is expected/unavoidable or not when any test is broken.
 *
 * <p><strong>IMPORTANT</strong>: Message serialization/deserialization by JSON
 * is to be able to create a proof of concept in simple.
 * This test do not intended serialization format stability.
 * Serialized JSON format may be different depending on the version.
 */
@Slf4j
public class MessageJsonReconstructionTest {
    private static final ObjectMapper objectMapper =
            TestUtil.objectMapperWithProductionConfiguration(false);

    @Test
    public void textMessageTest() {
        test(new TextMessage("TEST"));
    }

    @Test
    public void textMessageWithQuickReplyTest() {
        List<QuickReplyItem> items = asList(
                QuickReplyItem.builder()
                              .action(CameraAction.withLabel("Camera Action Label"))
                              .imageUrl(URI.create("https://example.com/image.png"))
                              .build(),
                QuickReplyItem.builder()
                              .action(CameraRollAction.withLabel("Camera Roll Action Label"))
                              .build(),
                QuickReplyItem.builder()
                              .action(LocationAction.withLabel("Location Action"))
                              .build()
        );

        TextMessage target = TextMessage
                .builder()
                .text("TEST")
                .quickReply(QuickReply.items(items))
                .build();

        test(target);
    }

    @Test
        final Image heroBlock =
                Image.builder()
                     .url("https://example.com/cafe.jpg")
                     .size(ImageSize.FullWidth)
                     .aspectRatio(ImageAspectRatio.R20to13)
                     .aspectMode(ImageAspectMode.Cover)
                     .action(new URIAction("label", "http://example.com"))
                     .build();

        final Box bodyBlock;
        {
            final Text title =
                    Text.builder().text("Brown Cafe").weight(TextWeight.Bold).size(FxFontSize.Xl).build();

            final Box review;
            {
                final Icon goldStar =
                        Icon.builder().size(FxFontSize.Sm).url("https://example.com/gold_star.png").build();
                final Icon grayStar =
                        Icon.builder().size(FxFontSize.Sm).url("https://example.com/gray_star.png").build();
                final Text point =
                        Text.builder()
                            .text("4.0")
                            .size(FxFontSize.Sm)
                            .color("#999999")
                            .margin(FxMarginSize.Md)
                            .flex(0)
                            .build();

                review = Box.builder()
                            .layout(FxLayout.Baseline)
                            .margin(FxMarginSize.Md)
                            .contents(Arrays.asList(goldStar, goldStar, goldStar, goldStar, grayStar, point))
                            .build();
            }
    @Test
    public void templateMessageWithCarouselTemplateTest() {
            {
                final Box place =
                        Box.builder()
                           .layout(FxLayout.Baseline)
                           .spacing(FxMarginSize.Sm)
                           .contents(
                                   Arrays.asList(
                                           Text.builder()
                                               .text("Place")
                                               .color("#aaaaaa")
                                               .size(FxFontSize.Sm)
                                               .flex(1)
                                               .build(),
                                           Text.builder()
                                               .text("Shinjuku, Tokyo")
                                               .wrap(true)
                                               .color("#666666")
                                               .size(FxFontSize.Sm)
                                               .flex(5)
                                               .build()
                                   )
        final ButtonsTemplate buttonsTemplate =
                           .build();
                final Box time =
                        Box.builder()
                           .layout(FxLayout.Baseline)
                           .spacing(FxMarginSize.Sm)
                           .contents(
                                   Arrays.asList(
                                           Text.builder()
                                               .text("Time")
                                               .color("#aaaaaa")
                                               .size(FxFontSize.Sm)
                                               .flex(1)
                                               .build(),
                                           Text.builder()
                                               .text("10:00 - 23:00")
                                               .wrap(true)
                                               .color("#666666")
                                               .size(FxFontSize.Sm)
                                               .flex(5)
                                               .build()
                                   )
        final Multicast multicast3 =
                           .build();

                info = Box.builder()
                          .layout(FxLayout.Vertical)
                          .margin(FxMarginSize.Lg)
                          .spacing(FxMarginSize.Sm)
                          .contents(Arrays.asList(place, time))
                          .build();
            }

            bodyBlock = Box.builder()
                      .layout(FxLayout.Vertical)
                      .contents(Arrays.asList(title, review, info))
                      .build();
        }

        final Box footerBlock;
        {
            final Spacer spacer = Spacer.builder().size(FxMarginSize.Sm).build();
            final Button callAction =
                    Button.builder()
                          .style(ButtonStyle.Link)
    @Test
    public void narrowcast() {
        test(GenderDemographicFilter.builder()
                                    .oneOf(Collections.singletonList(Gender.MALE))
                                    .build());

        final Narrowcast narrowcast = new Narrowcast(
                new TextMessage("text"),
                Filter.builder()
                          .build();

            footerBlock = Box.builder()
                        .layout(FxLayout.Vertical)
                        .spacing(FxMarginSize.Sm)
                        .contents(Arrays.asList(spacer, callAction, separator, websiteAction))
                        .build();
        }

        test(AgeDemographicFilter.builder()
                                 .gte(Age.AGE_15)
                                 .lt(Age.AGE_25)
                                 .build());
        test(AppTypeDemographicFilter.builder()
                                     .oneOf(Collections.singletonList(AppType.IOS))
                                     .build());
        test(AreaDemographicFilter.builder()
                                  .oneOf(Collections.singletonList(AreaCode.JP_TOKYO))
                                  .build());
        test(SubscriptionPeriodDemographicFilter.builder()
                                                .gte(SubscriptionPeriod.DAY_7)
                                                .lt(SubscriptionPeriod.DAY_30)
                                                .build());
        test(OperatorDemographicFilter
                     .builder()
                     .and(Arrays.asList(AgeDemographicFilter.builder()
                                                            .gte(Age.AGE_15)
                                                            .lt(Age.AGE_25)
                                                            .build(),
                                        AppTypeDemographicFilter.builder()
                                                                .oneOf(Collections.singletonList(AppType.IOS))
                                                                .build()))
                     .build());
    }

    @Test
    public void datetimePickerActionTest() {
        final DatetimePickerAction<LocalDate> datePickerAction =
                OfLocalDate.builder()
                           .label("labal")
                           .data("postback")
                           .initial(LocalDate.of(2017, 9, 8))
                           .min(LocalDate.of(2017, 9, 8))
                           .max(LocalDate.of(2017, 9, 8))
                           .build();

        final DatetimePickerAction<LocalTime> timePickerAction =
                OfLocalTime.builder()
                           .label("labal")
                           .data("postback")
                           .initial(LocalTime.of(14, 55))
                           .max(LocalTime.of(14, 55))
                           .min(LocalTime.of(14, 55))
                           .build();

        final DatetimePickerAction<LocalDateTime> datetimePickerAction =
                OfLocalDatetime.builder()
                               .label("labal")
                               .data("postback")
                               .initial(LocalDateTime.of(2017, 9, 8, 14, 55))
                               .max(LocalDateTime.of(2017, 9, 8, 14, 55))
                               .min(LocalDateTime.of(2017, 9, 8, 14, 55))
                               .build();

        final ButtonsTemplate buttonsTemplate =
                new ButtonsTemplate(URI.create("https://example.com"), "title", "text",
                                    ImmutableList.of(datePickerAction, timePickerAction, datetimePickerAction));

        test(new TemplateMessage("ALT_TEXT", buttonsTemplate));
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    void test(final Object original) {
        final Object reconstructed = serializeThenDeserialize(original);
        assertThat(reconstructed).isEqualTo(original);
    }

    @SneakyThrows
    Object serializeThenDeserialize(final Object original) {
        log.info("Original:      {}", original);
        final String asJson = objectMapper.writeValueAsString(original);
        log.info("AS JSON:       {}", asJson);
        final Object reconstructed = objectMapper.readValue(asJson, original.getClass());
        log.info("Reconstructed: {}", reconstructed);

        return reconstructed;
    }
}

<MSG> Flex message support: address review's comment

<DFF> @@ -28,9 +28,9 @@ import com.linecorp.bot.model.message.flex.component.Spacer;
 import com.linecorp.bot.model.message.flex.component.Text;
 import com.linecorp.bot.model.message.flex.component.Text.TextWeight;
 import com.linecorp.bot.model.message.flex.container.Bubble;
-import com.linecorp.bot.model.message.flex.unit.FxFontSize;
-import com.linecorp.bot.model.message.flex.unit.FxLayout;
-import com.linecorp.bot.model.message.flex.unit.FxMarginSize;
+import com.linecorp.bot.model.message.flex.unit.FlexFontSize;
+import com.linecorp.bot.model.message.flex.unit.FlexLayout;
+import com.linecorp.bot.model.message.flex.unit.FlexMarginSize;
 import com.linecorp.bot.model.message.imagemap.ImagemapBaseSize;
 import com.linecorp.bot.model.message.template.ButtonsTemplate;
 import com.linecorp.bot.model.message.template.CarouselColumn;
@@ -121,8 +121,8 @@ public class MessageJsonReconstructionTest {
         final Image heroBlock =
                 Image.builder()
                      .url("https://example.com/cafe.jpg")
-                     .size(ImageSize.FullWidth)
-                     .aspectRatio(ImageAspectRatio.R20to13)
+                     .size(ImageSize.FULL_WIDTH)
+                     .aspectRatio(ImageAspectRatio.R20TO13)
                      .aspectMode(ImageAspectMode.Cover)
                      .action(new URIAction("label", "http://example.com"))
                      .build();
@@ -130,26 +130,26 @@ public class MessageJsonReconstructionTest {
         final Box bodyBlock;
         {
             final Text title =
-                    Text.builder().text("Brown Cafe").weight(TextWeight.Bold).size(FxFontSize.Xl).build();
+                    Text.builder().text("Brown Cafe").weight(TextWeight.BOLD).size(FlexFontSize.XL).build();
 
             final Box review;
             {
                 final Icon goldStar =
-                        Icon.builder().size(FxFontSize.Sm).url("https://example.com/gold_star.png").build();
+                        Icon.builder().size(FlexFontSize.SM).url("https://example.com/gold_star.png").build();
                 final Icon grayStar =
-                        Icon.builder().size(FxFontSize.Sm).url("https://example.com/gray_star.png").build();
+                        Icon.builder().size(FlexFontSize.SM).url("https://example.com/gray_star.png").build();
                 final Text point =
                         Text.builder()
                             .text("4.0")
-                            .size(FxFontSize.Sm)
+                            .size(FlexFontSize.SM)
                             .color("#999999")
-                            .margin(FxMarginSize.Md)
+                            .margin(FlexMarginSize.MD)
                             .flex(0)
                             .build();
 
                 review = Box.builder()
-                            .layout(FxLayout.Baseline)
-                            .margin(FxMarginSize.Md)
+                            .layout(FlexLayout.BASELINE)
+                            .margin(FlexMarginSize.MD)
                             .contents(Arrays.asList(goldStar, goldStar, goldStar, goldStar, grayStar, point))
                             .build();
             }
@@ -158,21 +158,21 @@ public class MessageJsonReconstructionTest {
             {
                 final Box place =
                         Box.builder()
-                           .layout(FxLayout.Baseline)
-                           .spacing(FxMarginSize.Sm)
+                           .layout(FlexLayout.BASELINE)
+                           .spacing(FlexMarginSize.SM)
                            .contents(
                                    Arrays.asList(
                                            Text.builder()
                                                .text("Place")
                                                .color("#aaaaaa")
-                                               .size(FxFontSize.Sm)
+                                               .size(FlexFontSize.SM)
                                                .flex(1)
                                                .build(),
                                            Text.builder()
                                                .text("Shinjuku, Tokyo")
                                                .wrap(true)
                                                .color("#666666")
-                                               .size(FxFontSize.Sm)
+                                               .size(FlexFontSize.SM)
                                                .flex(5)
                                                .build()
                                    )
@@ -180,21 +180,21 @@ public class MessageJsonReconstructionTest {
                            .build();
                 final Box time =
                         Box.builder()
-                           .layout(FxLayout.Baseline)
-                           .spacing(FxMarginSize.Sm)
+                           .layout(FlexLayout.BASELINE)
+                           .spacing(FlexMarginSize.SM)
                            .contents(
                                    Arrays.asList(
                                            Text.builder()
                                                .text("Time")
                                                .color("#aaaaaa")
-                                               .size(FxFontSize.Sm)
+                                               .size(FlexFontSize.SM)
                                                .flex(1)
                                                .build(),
                                            Text.builder()
                                                .text("10:00 - 23:00")
                                                .wrap(true)
                                                .color("#666666")
-                                               .size(FxFontSize.Sm)
+                                               .size(FlexFontSize.SM)
                                                .flex(5)
                                                .build()
                                    )
@@ -202,22 +202,22 @@ public class MessageJsonReconstructionTest {
                            .build();
 
                 info = Box.builder()
-                          .layout(FxLayout.Vertical)
-                          .margin(FxMarginSize.Lg)
-                          .spacing(FxMarginSize.Sm)
+                          .layout(FlexLayout.VERTICAL)
+                          .margin(FlexMarginSize.LG)
+                          .spacing(FlexMarginSize.SM)
                           .contents(Arrays.asList(place, time))
                           .build();
             }
 
             bodyBlock = Box.builder()
-                      .layout(FxLayout.Vertical)
+                      .layout(FlexLayout.VERTICAL)
                       .contents(Arrays.asList(title, review, info))
                       .build();
         }
 
         final Box footerBlock;
         {
-            final Spacer spacer = Spacer.builder().size(FxMarginSize.Sm).build();
+            final Spacer spacer = Spacer.builder().size(FlexMarginSize.SM).build();
             final Button callAction =
                     Button.builder()
                           .style(ButtonStyle.Link)
@@ -233,8 +233,8 @@ public class MessageJsonReconstructionTest {
                           .build();
 
             footerBlock = Box.builder()
-                        .layout(FxLayout.Vertical)
-                        .spacing(FxMarginSize.Sm)
+                        .layout(FlexLayout.VERTICAL)
+                        .spacing(FlexMarginSize.SM)
                         .contents(Arrays.asList(spacer, callAction, separator, websiteAction))
                         .build();
         }

{'addition_count': 27, 'commit_subject': "Flex message support: address review's comment", 'deletion_count': 27, 'file_extension': '.java', 'lang': 'java', 'license': 'apache-2.0', 'repo_name': 'line/line-bot-sdk-java'}