diff --git a/eclipse/VaadinJavaConventions.xml b/eclipse/VaadinJavaConventions.xml index 7f9391169a0..6d9d57cb742 100644 --- a/eclipse/VaadinJavaConventions.xml +++ b/eclipse/VaadinJavaConventions.xml @@ -48,7 +48,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -242,7 +242,7 @@ - + diff --git a/flow-client/src/main/java/com/vaadin/client/communication/MessageSender.java b/flow-client/src/main/java/com/vaadin/client/communication/MessageSender.java index 9a563ff153b..6182fde8123 100644 --- a/flow-client/src/main/java/com/vaadin/client/communication/MessageSender.java +++ b/flow-client/src/main/java/com/vaadin/client/communication/MessageSender.java @@ -209,7 +209,7 @@ public void send(final JsonObject payload) { pushPendingMessage = payload; push.push(payload); } else { - Console.log("send XHR"); + Console.debug("send XHR"); registry.getXhrConnection().send(payload); } } diff --git a/flow-data/src/main/java/com/vaadin/flow/data/binder/HasValidator.java b/flow-data/src/main/java/com/vaadin/flow/data/binder/HasValidator.java index aacc0fabcf9..992ef8fcbc6 100644 --- a/flow-data/src/main/java/com/vaadin/flow/data/binder/HasValidator.java +++ b/flow-data/src/main/java/com/vaadin/flow/data/binder/HasValidator.java @@ -74,31 +74,31 @@ default Validator getDefaultValidator() { * public class DatePickerDemo implements HasValidator<LocalDate> { * * // Each web component has a way to communicate its validation status - * // to its server-side component instance. The following clientSideValid - * // state is introduced here just for the sake of simplicity of this code - * // snippet: + * // to its server-side component instance. The following + * // clientSideValid state is introduced here just for the sake of + * // simplicity of this code snippet: * boolean clientSideValid = true; * * /** - * * Note how clientSideValid engaged in the definition - * * of this method. It is important to reflect this status either - * * in the returning validation result of this method or any other - * * validation that is associated with this component. - * */ + * * Note how clientSideValid engaged in the definition of + * * this method. It is important to reflect this status either in the + * * returning validation result of this method or any other validation + * * that is associated with this component. + * */ * @Override * public Validator getDefaultValidator() { - * return (value, valueContext) -> clientSideValid ? ValidationResult.ok() + * return (value, valueContext) -> clientSideValid + * ? ValidationResult.ok() * : ValidationResult.error("Invalid date format"); * } * - * private final Collection<ValidationStatusChangeListener<LocalDate>> - * validationStatusListeners = new ArrayList<>(); + * private final Collection<ValidationStatusChangeListener<LocalDate>> validationStatusListeners = new ArrayList<>(); * * /** * * This enables the binding to subscribe for the validation status * * change events that are fired by this component and revalidate * * itself respectively. - * */ + * */ * @Override * public Registration addValidationStatusChangeListener( * ValidationStatusChangeListener<LocalDate> listener) { diff --git a/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java b/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java index 7908c0115a7..ad2d6eb8363 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java @@ -1314,14 +1314,18 @@ public void fetchFromProvider_disablePaging_singleQueryWithLimit() { @Test public void fetchFromProvider_maxLimitValue_pagesCalculatedProperly() { - AbstractDataProviderdataProvider=createDataProvider(42);dataProvider=Mockito.spy(dataProvider); + AbstractDataProvider dataProvider = createDataProvider( + 42); + dataProvider = Mockito.spy(dataProvider); - dataCommunicator.setDataProvider(dataProvider,null);dataCommunicator.setPageSize(2_000_000_000); + dataCommunicator.setDataProvider(dataProvider, null); + dataCommunicator.setPageSize(2_000_000_000); // We check the page number calculation does not lead to integer // overflow, and not throw thus - dataCommunicator.fetchFromProvider(0,Integer.MAX_VALUE); + dataCommunicator.fetchFromProvider(0, Integer.MAX_VALUE); - Mockito.verify(dataProvider,Mockito.times(1)).fetch(Mockito.any(Query.class)); + Mockito.verify(dataProvider, Mockito.times(1)) + .fetch(Mockito.any(Query.class)); } @Test diff --git a/flow-data/src/test/java/com/vaadin/flow/data/validator/BeanValidatorTest.java b/flow-data/src/test/java/com/vaadin/flow/data/validator/BeanValidatorTest.java index 4f11446bc71..7ad2890f99a 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/validator/BeanValidatorTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/validator/BeanValidatorTest.java @@ -69,7 +69,8 @@ public void testInvalidDecimalsFailsInFrench() { @Test public void testAddressNestedPropertyInvalidPostalCodeFails() { - assertFails(100_000,"must be less than or equal to 99999",validator("address.postalCode")); + assertFails(100_000, "must be less than or equal to 99999", + validator("address.postalCode")); } @Test diff --git a/flow-data/src/test/java/com/vaadin/flow/data/validator/RangeValidatorTest.java b/flow-data/src/test/java/com/vaadin/flow/data/validator/RangeValidatorTest.java index 1f55fb198cd..283158f24cb 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/validator/RangeValidatorTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/validator/RangeValidatorTest.java @@ -109,9 +109,12 @@ public void testNullLessThanEverything() { @Test public void testDateRange() { - RangeValidatorv=RangeValidator.of("Date must be in 2016",LocalDate.of(2016,1,1),LocalDate.of(2016,12,31)); + RangeValidator v = RangeValidator.of("Date must be in 2016", + LocalDate.of(2016, 1, 1), LocalDate.of(2016, 12, 31)); - assertFails(LocalDate.ofEpochDay(0),v);assertPasses(LocalDate.of(2016,7,31),v);assertFails(LocalDate.ofEpochDay(1_000_000_000),v); + assertFails(LocalDate.ofEpochDay(0), v); + assertPasses(LocalDate.of(2016, 7, 31), v); + assertFails(LocalDate.ofEpochDay(1_000_000_000), v); } } diff --git a/flow-server/src/main/java/com/vaadin/experimental/FeatureFlags.java b/flow-server/src/main/java/com/vaadin/experimental/FeatureFlags.java index a2431265070..cb3009ad498 100644 --- a/flow-server/src/main/java/com/vaadin/experimental/FeatureFlags.java +++ b/flow-server/src/main/java/com/vaadin/experimental/FeatureFlags.java @@ -67,11 +67,6 @@ public class FeatureFlags implements Serializable { "collaborationEngineBackend", "https://github.com/vaadin/platform/issues/1988", true, null); - public static final Feature WEB_PUSH = new Feature( - "Server side WebPush API", "webPush", - "https://vaadin.com/docs/latest/configuration/setting-up-webpush", - true, "com.vaadin.flow.server.webpush.WebPush"); - public static final Feature FORM_FILLER_ADDON = new Feature( "Form Filler Add-on", "formFillerAddon", "https://github.com/vaadin/form-filler-addon", true, @@ -112,7 +107,6 @@ public FeatureFlags(Lookup lookup) { this.lookup = lookup; features.add(new Feature(EXAMPLE)); features.add(new Feature(COLLABORATION_ENGINE_BACKEND)); - features.add(new Feature(WEB_PUSH)); features.add(new Feature(FORM_FILLER_ADDON)); features.add(new Feature(HILLA_I18N)); features.add(new Feature(HILLA_FULLSTACK_SIGNALS)); diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentTracker.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentTracker.java index cb6e153b6ff..611424b5d94 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentTracker.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentTracker.java @@ -17,6 +17,7 @@ import java.io.File; import java.io.Serializable; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -47,6 +48,10 @@ public class ComponentTracker { .synchronizedMap(new WeakHashMap<>()); private static Map attachLocation = Collections .synchronizedMap(new WeakHashMap<>()); + private static Map createLocations = Collections + .synchronizedMap(new WeakHashMap<>()); + private static Map attachLocations = Collections + .synchronizedMap(new WeakHashMap<>()); private static Boolean disabled = null; private static String[] prefixesToSkip = new String[] { @@ -190,6 +195,18 @@ public static Location findCreate(Component component) { return createLocation.get(component); } + /** + * Finds the locations related to where the given component instance was + * created. + * + * @param component + * the component to find + * @return the locations involved in creating the component + */ + public static Location[] findCreateLocations(Component component) { + return createLocations.get(component); + } + /** * Tracks the location where the component was created. This should be * called from the Component constructor so that the creation location can @@ -203,12 +220,14 @@ public static void trackCreate(Component component) { return; } StackTraceElement[] stack = Thread.currentThread().getStackTrace(); - Location location = findRelevantLocation(component.getClass(), stack, - null); + Location[] relevantLocations = findRelevantLocations(stack); + Location location = findRelevantLocation(component.getClass(), + relevantLocations, null); if (isNavigatorCreate(location)) { - location = findRelevantLocation(null, stack, null); + location = findRelevantLocation(null, relevantLocations, null); } createLocation.put(component, location); + createLocations.put(component, relevantLocations); } /** @@ -223,6 +242,18 @@ public static Location findAttach(Component component) { return attachLocation.get(component); } + /** + * Finds the locations related to where the given component instance was + * attached to a parent. + * + * @param component + * the component to find + * @return the locations involved in creating the component + */ + public static Location[] findAttachLocations(Component component) { + return attachLocations.get(component); + } + /** * Tracks the location where the component was attached. This should be * called from the Component attach logic so that the creation location can @@ -239,14 +270,16 @@ public static void trackAttach(Component component) { // In most cases the interesting attach call is found in the same class // where the component was created and not in a generic layout class - Location location = findRelevantLocation(component.getClass(), stack, - findCreate(component)); + Location[] relevantLocations = findRelevantLocations(stack); + Location location = findRelevantLocation(component.getClass(), + relevantLocations, findCreate(component)); if (isNavigatorCreate(location)) { // For routes, we can just show the init location as we have nothing // better location = createLocation.get(component); } attachLocation.put(component, location); + attachLocations.put(component, relevantLocations); } /** @@ -283,30 +316,41 @@ private static boolean isNavigatorCreate(Location location) { .equals(AbstractNavigationStateRenderer.class.getName()); } + private static Location[] findRelevantLocations(StackTraceElement[] stack) { + return Stream.of(stack).filter(e -> { + for (String prefixToSkip : prefixesToSkip) { + if (e.getClassName().startsWith(prefixToSkip)) { + return false; + } + } + return true; + }).map(ComponentTracker::toLocation).toArray(Location[]::new); + } + private static Location findRelevantLocation( - Class excludeClass, StackTraceElement[] stack, + Class excludeClass, Location[] locations, Location preferredClass) { - List candidates = Stream.of(stack) - .filter(e -> excludeClass == null - || !e.getClassName().equals(excludeClass.getName())) - .filter(e -> { + List candidates = Arrays.stream(locations) + .filter(location -> excludeClass == null + || !location.className().equals(excludeClass.getName())) + .filter(location -> { for (String prefixToSkip : prefixesToSkip) { - if (e.getClassName().startsWith(prefixToSkip)) { + if (location.className().startsWith(prefixToSkip)) { return false; } } return true; }).collect(Collectors.toList()); if (preferredClass != null) { - Optional preferredCandidate = candidates.stream() - .filter(e -> e.getClassName() + Optional preferredCandidate = candidates.stream() + .filter(location -> location.className() .equals(preferredClass.className())) .findFirst(); if (preferredCandidate.isPresent()) { - return toLocation(preferredCandidate.get()); + return preferredCandidate.get(); } } - return toLocation(candidates.stream().findFirst().orElse(null)); + return candidates.isEmpty() ? null : candidates.get(0); } /** diff --git a/flow-server/src/main/java/com/vaadin/flow/router/MenuData.java b/flow-server/src/main/java/com/vaadin/flow/router/MenuData.java index becfcdfac4c..1c326b25887 100644 --- a/flow-server/src/main/java/com/vaadin/flow/router/MenuData.java +++ b/flow-server/src/main/java/com/vaadin/flow/router/MenuData.java @@ -26,7 +26,8 @@ *

* Only for read as data is immutable. */ -public record MenuData(String title, Double order, boolean exclude, String icon, Class menuClass) implements Serializable { +public record MenuData(String title, Double order, boolean exclude, String icon, + Class menuClass) implements Serializable { /** * MenuData constructor. diff --git a/flow-server/src/main/java/com/vaadin/flow/server/dau/DAUUtils.java b/flow-server/src/main/java/com/vaadin/flow/server/dau/DAUUtils.java index a949eea77dd..9f574b224fe 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/dau/DAUUtils.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/dau/DAUUtils.java @@ -322,7 +322,7 @@ private static VaadinRequest createVaadinRequest( * the enforcement messages or null if enforcement should not be * applied * @param origin - * the exception that caused the enforcement + * the exception that caused the enforcement * @param endRequestAction * the action to be run at the end of the request */ diff --git a/flow-server/src/main/java/com/vaadin/flow/server/menu/AvailableViewInfo.java b/flow-server/src/main/java/com/vaadin/flow/server/menu/AvailableViewInfo.java index e4012e9fd49..89e78b19d63 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/menu/AvailableViewInfo.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/menu/AvailableViewInfo.java @@ -29,22 +29,32 @@ /** * Represents a view configuration for use with a menu. * - * @param title title of view - * @param rolesAllowed logged in roles allowed for view - * @param loginRequired requires login - * @param route path string - * @param lazy lazy loaded - * @param register register view - * @param menu menu item information - * @param children view children - * @param routeParameters view parameters - * @param flowLayout if server layout should be used + * @param title + * title of view + * @param rolesAllowed + * logged in roles allowed for view + * @param loginRequired + * requires login + * @param route + * path string + * @param lazy + * lazy loaded + * @param register + * register view + * @param menu + * menu item information + * @param children + * view children + * @param routeParameters + * view parameters + * @param flowLayout + * if server layout should be used */ public record AvailableViewInfo(String title, String[] rolesAllowed, - boolean loginRequired, String route, boolean lazy, - boolean register, MenuData menu, - List children, @JsonProperty( - "params") Map routeParameters, boolean flowLayout) implements Serializable { + boolean loginRequired, String route, boolean lazy, boolean register, + MenuData menu, List children, + @JsonProperty("params") Map routeParameters, + boolean flowLayout) implements Serializable { @Override public boolean equals(final Object o) { @@ -67,22 +77,20 @@ public boolean equals(final Object o) { @Override public int hashCode() { - int result = Objects.hash(title, loginRequired, route, lazy, register, menu, routeParameters); + int result = Objects.hash(title, loginRequired, route, lazy, register, + menu, routeParameters); result = 31 * result + Arrays.hashCode(rolesAllowed); return result; } @Override public String toString() { - return "AvailableViewInfo{" + "title='" + title - + '\'' + ", rolesAllowed=" + Arrays.toString(rolesAllowed) - + ", loginRequired=" + loginRequired - + ", route='" + route + '\'' - + ", lazy=" + lazy - + ", register=" + register - + ", menu=" + menu - + ", flowLayout=" + flowLayout - + ", routeParameters=" + routeParameters + '}'; + return "AvailableViewInfo{" + "title='" + title + '\'' + + ", rolesAllowed=" + Arrays.toString(rolesAllowed) + + ", loginRequired=" + loginRequired + ", route='" + route + + '\'' + ", lazy=" + lazy + ", register=" + register + ", menu=" + + menu + ", flowLayout=" + flowLayout + ", routeParameters=" + + routeParameters + '}'; } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/menu/MenuEntry.java b/flow-server/src/main/java/com/vaadin/flow/server/menu/MenuEntry.java index 8d3944a6606..3c89f9b5764 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/menu/MenuEntry.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/menu/MenuEntry.java @@ -40,6 +40,6 @@ * annotation or null if not available. Always null for * Hilla/TypeScript client views. */ -public record MenuEntry(String path, String title, Double order, - String icon, Class menuClass) implements Serializable { +public record MenuEntry(String path, String title, Double order, String icon, + Class menuClass) implements Serializable { } diff --git a/flow-tests/pom.xml b/flow-tests/pom.xml index 6d6038f5412..f3b48426459 100644 --- a/flow-tests/pom.xml +++ b/flow-tests/pom.xml @@ -292,7 +292,7 @@ test-router-custom-context test-live-reload test-live-reload-multimodule - test-live-reload-multimodule/pom-devbundle.xml + test-live-reload-multimodule-devbundle test-redeployment test-redeployment-no-cache diff --git a/flow-tests/test-frontend/pom.xml b/flow-tests/test-frontend/pom.xml index 9be65dd7f3a..2fc3e33f22b 100644 --- a/flow-tests/test-frontend/pom.xml +++ b/flow-tests/test-frontend/pom.xml @@ -33,8 +33,8 @@ vite-basics vite-production vite-production-custom-frontend - vite-context-path/pom-production.xml vite-context-path + vite-context-path/pom-production.xml vite-pwa vite-pwa-custom-offline-path vite-pwa-custom-offline-path/pom-production.xml @@ -49,17 +49,17 @@ vite-embedded-webcomponent-resync-ws vite-embedded-webcomponent-resync-wsxhr vite-embedded-webcomponent-resync-longpolling - test-npm/pom-production.xml test-npm - test-pnpm/pom-production.xml + test-npm/pom-production.xml test-pnpm + test-pnpm/pom-production.xml bun - test-bun/pom-production.xml test-bun + test-bun/pom-production.xml diff --git a/flow-tests/test-live-reload-multimodule/pom-devbundle.xml b/flow-tests/test-live-reload-multimodule-devbundle/pom.xml similarity index 87% rename from flow-tests/test-live-reload-multimodule/pom-devbundle.xml rename to flow-tests/test-live-reload-multimodule-devbundle/pom.xml index 63cd03a0c8b..ead96925106 100644 --- a/flow-tests/test-live-reload-multimodule/pom-devbundle.xml +++ b/flow-tests/test-live-reload-multimodule-devbundle/pom.xml @@ -42,9 +42,9 @@ - library/pom-devbundle.xml - ui/pom-devbundle.xml - theme/pom-devbundle.xml + ../test-live-reload-multimodule/library/pom-devbundle.xml + ../test-live-reload-multimodule/ui/pom-devbundle.xml + ../test-live-reload-multimodule/theme/pom-devbundle.xml diff --git a/flow-tests/test-live-reload-multimodule/library/pom-devbundle.xml b/flow-tests/test-live-reload-multimodule/library/pom-devbundle.xml index e5529a5e0b6..76767d24713 100644 --- a/flow-tests/test-live-reload-multimodule/library/pom-devbundle.xml +++ b/flow-tests/test-live-reload-multimodule/library/pom-devbundle.xml @@ -7,7 +7,7 @@ flow-test-live-reload-multimodule-devbundle com.vaadin 24.6-SNAPSHOT - ../pom-devbundle.xml + ../../test-live-reload-multimodule-devbundle/pom.xml flow-test-live-reload-multimodule-library-devbundle The frontend library module for a live reload multi module project (dev bundle) diff --git a/flow-tests/test-live-reload-multimodule/theme/pom-devbundle.xml b/flow-tests/test-live-reload-multimodule/theme/pom-devbundle.xml index a6ac3acc992..c2232823af8 100644 --- a/flow-tests/test-live-reload-multimodule/theme/pom-devbundle.xml +++ b/flow-tests/test-live-reload-multimodule/theme/pom-devbundle.xml @@ -7,7 +7,7 @@ flow-test-live-reload-multimodule-devbundle com.vaadin 24.6-SNAPSHOT - ../pom-devbundle.xml + ../../test-live-reload-multimodule-devbundle/pom.xml flow-test-live-reload-multimodule-theme-devbundle The theme module for a live reload multi module project (dev bundle) diff --git a/flow-tests/test-live-reload-multimodule/ui/pom-devbundle.xml b/flow-tests/test-live-reload-multimodule/ui/pom-devbundle.xml index 52fd786f81d..d69c158d160 100644 --- a/flow-tests/test-live-reload-multimodule/ui/pom-devbundle.xml +++ b/flow-tests/test-live-reload-multimodule/ui/pom-devbundle.xml @@ -7,7 +7,7 @@ flow-test-live-reload-multimodule-devbundle com.vaadin 24.6-SNAPSHOT - ../pom-devbundle.xml + ../../test-live-reload-multimodule-devbundle/pom.xml flow-test-live-reload-multimodule-ui-devbundle The UI module for a live reload multi module project (dev bundle) diff --git a/flow-tests/test-webpush/src/main/java/com/vaadin/flow/webpush/WebPushView.java b/flow-tests/test-webpush/src/main/java/com/vaadin/flow/webpush/WebPushView.java index c9ae1667276..c26c65cbd6e 100644 --- a/flow-tests/test-webpush/src/main/java/com/vaadin/flow/webpush/WebPushView.java +++ b/flow-tests/test-webpush/src/main/java/com/vaadin/flow/webpush/WebPushView.java @@ -18,14 +18,13 @@ import java.util.List; -import nl.martijndwars.webpush.Subscription; - import com.vaadin.flow.component.Text; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.NativeButton; import com.vaadin.flow.router.Route; import com.vaadin.flow.server.webpush.WebPush; import com.vaadin.flow.server.webpush.WebPushMessage; +import com.vaadin.flow.server.webpush.WebPushSubscription; @Route("") public class WebPushView extends Div { @@ -52,7 +51,7 @@ public class WebPushView extends Div { "https://upload.wikimedia.org/wikipedia/commons/0/0e/Message-icon-blue-symbol-double.png" ); - private Subscription subscription; + private WebPushSubscription subscription; public WebPushView() { webPush = new WebPush(PUBLIC_KEY, PRIVATE_KEY, "test"); diff --git a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPush.java b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPush.java index 01f6fdfbf42..45908906e91 100644 --- a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPush.java +++ b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPush.java @@ -32,14 +32,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.vaadin.experimental.FeatureFlags; import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.UI; import com.vaadin.flow.component.page.Page; import com.vaadin.flow.component.page.PendingJavaScriptResult; import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.internal.StringUtil; -import com.vaadin.flow.server.VaadinService; import elemental.json.Json; import elemental.json.JsonObject; @@ -77,11 +75,6 @@ public class WebPush { * Subject used in the JWT payload (for VAPID). */ public WebPush(String publicKey, String privateKey, String subject) { - if (!FeatureFlags.get(VaadinService.getCurrent().getContext()) - .isEnabled(FeatureFlags.WEB_PUSH)) { - throw new WebPushException("WebPush feature is not enabled. " - + "Add `com.vaadin.experimental.webPush=true` to `vaadin-featureflags.properties`file in resources to enable feature."); - } this.publicKey = publicKey; Security.addProvider(new BouncyCastleProvider()); @@ -109,13 +102,20 @@ public WebPush(String publicKey, String privateKey, String subject) { * @throws WebPushException * if sending a notification fails */ - public void sendNotification(Subscription subscription, + public void sendNotification(WebPushSubscription subscription, WebPushMessage message) throws WebPushException { int statusCode = -1; HttpResponse response = null; try { + Subscription.Keys keys = null; + if (subscription.keys() != null) { + keys = new Subscription.Keys(subscription.keys().p256dh(), + subscription.keys().auth()); + } + Subscription nativeSubscription = new Subscription( + subscription.endpoint(), keys); Notification notification = Notification.builder() - .subscription(subscription).payload(message.toJson()) + .subscription(nativeSubscription).payload(message.toJson()) .build(); response = pushService.send(notification, PushService.DEFAULT_ENCODING, @@ -282,11 +282,13 @@ private SerializableConsumer handlePossiblyEmptySubscription( }; } - private Subscription generateSubscription(JsonObject subscriptionJson) { - Subscription.Keys keys = new Subscription.Keys( + private WebPushSubscription generateSubscription( + JsonObject subscriptionJson) { + WebPushKeys keys = new WebPushKeys( subscriptionJson.getObject("keys").getString("p256dh"), subscriptionJson.getObject("keys").getString("auth")); - return new Subscription(subscriptionJson.getString("endpoint"), keys); + return new WebPushSubscription(subscriptionJson.getString("endpoint"), + keys); } private Logger getLogger() { diff --git a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushKeys.java b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushKeys.java new file mode 100644 index 00000000000..51410fe527a --- /dev/null +++ b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushKeys.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2024 Vaadin Ltd. + * + * Licensed 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.vaadin.flow.server.webpush; + +import java.io.Serializable; + +/** + * Holds the keys that used to encrypt the Web Push notification payload, so + * that only the current browser can read (decrypt) the content of + * notifications. + * + * @param p256dh + * public key on the P-256 curve. + * @param auth + * An authentication secret. + * @see PushSubscription + * Keys mdn web docs + */ +public record WebPushKeys(String p256dh, String auth) implements Serializable { +} diff --git a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushMessage.java b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushMessage.java index 01474ead43a..505d291f7ad 100644 --- a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushMessage.java +++ b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushMessage.java @@ -26,17 +26,22 @@ * * @since 24.2 */ -public record WebPushMessage(String title, ObjectNode options) implements Serializable { +public record WebPushMessage(String title, + ObjectNode options) implements Serializable { private static final ObjectMapper objectMapper = new ObjectMapper(); /** - * Creates a new Web Push notification message with the specified title and various options - * fetched from a given Java object. + * Creates a new Web Push notification message with the specified title and + * various options fetched from a given Java object. * - * @param title the notification title - * @param options any {@code Serializable} Java object representing custom settings to apply to the notification - * @see + * @param title + * the notification title + * @param options + * any {@code Serializable} Java object representing custom + * settings to apply to the notification + * @see * showNotification parameters */ public WebPushMessage(String title, Serializable options) { @@ -46,8 +51,10 @@ public WebPushMessage(String title, Serializable options) { /** * Creates a new Web Push notification message with just a title and body. * - * @param title notification title - * @param body notification body + * @param title + * notification title + * @param body + * notification body */ public WebPushMessage(String title, String body) { this(title, getBodyOption(body)); @@ -56,7 +63,8 @@ public WebPushMessage(String title, String body) { /** * Creates a new Web Push notification message with just a title. * - * @param title notification title + * @param title + * notification title */ public WebPushMessage(String title) { this(title, (ObjectNode) null); diff --git a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscription.java b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscription.java new file mode 100644 index 00000000000..d5a3acc5265 --- /dev/null +++ b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscription.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2024 Vaadin Ltd. + * + * Licensed 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.vaadin.flow.server.webpush; + +import java.io.Serializable; + +/** + * Represents a Web Push subscription that Push Manager gives back, when a user + * subscribes to push notifications in browser. + * + * @param endpoint + * a custom URL pointing to a push server, which can be used to send + * a push message to the particular service worker instance that + * subscribed to the push service. For this reason, it is a good idea + * to keep your endpoint a secret, so others do not hijack it and + * abuse the push functionality. + * @param keys + * an object containing the keys that used to encrypt the payload. + * @see PushSubscription + * mdn web docs + * @see PushManager + * mdn web docs + */ +public record WebPushSubscription(String endpoint, + WebPushKeys keys) implements Serializable { +} diff --git a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscriptionResponse.java b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscriptionResponse.java index 0aa58d47a1d..c6f66a0a45f 100644 --- a/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscriptionResponse.java +++ b/flow-webpush/src/main/java/com/vaadin/flow/server/webpush/WebPushSubscriptionResponse.java @@ -18,8 +18,6 @@ import java.io.Serializable; -import nl.martijndwars.webpush.Subscription; - /** * Callback for receiving web push subscription details * @@ -34,5 +32,5 @@ public interface WebPushSubscriptionResponse extends Serializable { * @param subscription * web push subscription object */ - void subscription(Subscription subscription); + void subscription(WebPushSubscription subscription); } diff --git a/flow-webpush/src/main/resources/META-INF/frontend/FlowWebPush.js b/flow-webpush/src/main/resources/META-INF/frontend/FlowWebPush.js index 44c399672b4..4b52b0a0893 100644 --- a/flow-webpush/src/main/resources/META-INF/frontend/FlowWebPush.js +++ b/flow-webpush/src/main/resources/META-INF/frontend/FlowWebPush.js @@ -30,8 +30,6 @@ window.Vaadin.Flow.webPush = window.Vaadin.Flow.webPush || { }); if (subscription) { - console.log(subscription); - // console.log(JSON.parse(JSON.stringify(subscription))); return JSON.parse(JSON.stringify(subscription)); } throw new Error("Subscription failed. See console for exception."); diff --git a/scripts/computeMatrix.js b/scripts/computeMatrix.js index f271bf98fd2..97354933526 100755 --- a/scripts/computeMatrix.js +++ b/scripts/computeMatrix.js @@ -109,12 +109,14 @@ const moduleWeights = { 'flow-tests/vaadin-spring-tests/test-spring-security-flow-standalone-routepathaccesschecker': { pos: 5, weight: 3 }, 'flow-tests/vaadin-spring-tests/test-spring-security-flow-routepathaccesschecker': { pos: 5, weight: 3 }, 'flow-tests/vaadin-spring-tests/test-mvc-without-endpoints': { pos: 5, weight: 2 }, + 'flow-tests/test-live-reload-multimodule': {pos:6}, 'flow-tests/test-live-reload-multimodule/ui': {pos:6}, 'flow-tests/test-live-reload-multimodule/library': {pos:6}, 'flow-tests/test-live-reload-multimodule/theme': {pos:6}, - 'flow-tests/test-live-reload-multimodule/ui/pom-devbundle.xml': {pos:6}, - 'flow-tests/test-live-reload-multimodule/library/pom-devbundle.xml': {pos:6}, - 'flow-tests/test-live-reload-multimodule/theme/pom-devbundle.xml': {pos:6}, + 'flow-tests/test-live-reload-multimodule-devbundle': {pos:6}, + 'flow-tests/test-live-reload-multimodule-devbundle/../test-live-reload-multimodule/ui/pom-devbundle.xml': {pos:6}, + 'flow-tests/test-live-reload-multimodule-devbundle/../test-live-reload-multimodule/library/pom-devbundle.xml': {pos:6}, + 'flow-tests/test-live-reload-multimodule-devbundle/../test-live-reload-multimodule/theme/pom-devbundle.xml': {pos:6}, 'flow-tests/test-redeployment': { weight: 13 }, 'flow-tests/test-pwa': { weight: 10 }, 'flow-tests/test-frontend/vite-pwa-disabled-offline': { weight: 7 }, diff --git a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ServerInfo.java b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ServerInfo.java index 3f590cde15b..32fdb367395 100644 --- a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ServerInfo.java +++ b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ServerInfo.java @@ -28,8 +28,8 @@ */ public class ServerInfo implements Serializable { - public record NameAndVersion(String name, String version) - implements Serializable { + public record NameAndVersion(String name, + String version) implements Serializable { }; private List versions = new ArrayList<>(); diff --git a/vaadin-spring/src/main/java/com/vaadin/flow/spring/io/FilterableResourceResolver.java b/vaadin-spring/src/main/java/com/vaadin/flow/spring/io/FilterableResourceResolver.java index 55e1f9c9689..5fdb95e810c 100644 --- a/vaadin-spring/src/main/java/com/vaadin/flow/spring/io/FilterableResourceResolver.java +++ b/vaadin-spring/src/main/java/com/vaadin/flow/spring/io/FilterableResourceResolver.java @@ -119,7 +119,8 @@ public class FilterableResourceResolver private List blockedJarsList; private record PackageInfo(Set allowedPackages, - Set blockedPackages, boolean blockedJar) implements Serializable { + Set blockedPackages, + boolean blockedJar) implements Serializable { } /** diff --git a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/NavigationAccessControlConfigurer.java b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/NavigationAccessControlConfigurer.java index 0793f9c8dd4..3a01283f367 100644 --- a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/NavigationAccessControlConfigurer.java +++ b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/NavigationAccessControlConfigurer.java @@ -55,7 +55,8 @@ * {@link NavigationAccessControlConfigurer} bean. * *

- * {@code @Bean
+ * {@code
+ * @Bean
  * NavigationAccessControlConfigurer navigationAccessControlConfigurer() {
  *     return new NavigationAccessControlConfigurer()
  *             .withRoutePathAccessChecker().withLoginView(LoginView.class);
@@ -70,7 +71,8 @@
  * prevent cyclic dependencies errors.
  *
  * 
- * {@code @Bean
+ * {@code
+ * @Bean
  * class SecurityConfig extends VaadinWebSecurity {
  *     static NavigationAccessControlConfigurer navigationAccessControlConfigurer() {
  *         return new NavigationAccessControlConfigurer()
diff --git a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/SpringAccessPathChecker.java b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/SpringAccessPathChecker.java
index 34433919a04..19e56925de6 100644
--- a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/SpringAccessPathChecker.java
+++ b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/SpringAccessPathChecker.java
@@ -42,7 +42,8 @@
  * method.
  *
  * 
- * {@code @Bean
+ * {@code
+ * @Bean
  * NavigationAccessControlConfigurer navigationAccessControlConfigurer() {
  *     return new NavigationAccessControlConfigurer()
  *             .withRoutePathAccessChecker().withLoginView(LoginView.class);
diff --git a/vaadin-spring/src/main/java/com/vaadin/flow/spring/springnative/VaadinHintsRegistrar.java b/vaadin-spring/src/main/java/com/vaadin/flow/spring/springnative/VaadinHintsRegistrar.java
index 1eddc1a9c49..530ac06ecd1 100644
--- a/vaadin-spring/src/main/java/com/vaadin/flow/spring/springnative/VaadinHintsRegistrar.java
+++ b/vaadin-spring/src/main/java/com/vaadin/flow/spring/springnative/VaadinHintsRegistrar.java
@@ -17,7 +17,10 @@
 import org.springframework.core.io.ClassPathResource;
 
 import com.vaadin.flow.di.LookupInitializer;
+import com.vaadin.flow.router.MenuData;
 import com.vaadin.flow.router.internal.DefaultErrorHandler;
+import com.vaadin.flow.server.menu.AvailableViewInfo;
+import com.vaadin.flow.server.menu.RouteParamType;
 
 /**
  * Registers runtime hints for Spring 3 native support.
@@ -106,7 +109,9 @@ private String[] getClasses() {
                 "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
                 "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper",
                 "com.fasterxml.jackson.databind.ser.std.ToStringSerializer",
-                DefaultErrorHandler.class.getName() };
+                DefaultErrorHandler.class.getName(), MenuData.class.getName(),
+                AvailableViewInfo.class.getName(),
+                RouteParamType.class.getName() };
     }
 
 }