Fix NPE in CatalogPropertyResolver

LayerGroupStyle.getLayers() or getStyles() may contain null references,
and that's expected.

Added comprehensive tests for CatalogPropertyResolver and ensured
all objects go through the apply() method with proper null checks
instead of directly through internal setCatalog() methods.
This commit is contained in:
Gabriel Roldan 2025-12-08 11:56:59 -03:00 committed by Gabriel Roldan
parent da9468a980
commit f5bf7a012c
2 changed files with 419 additions and 61 deletions

View File

@ -50,12 +50,11 @@ import org.geoserver.catalog.plugin.forwarding.ResolvingCatalogFacadeDecorator;
* facade.setOutboundResolver(resolver);
* </pre>
*
* @param <T> The type of {@link Info} to resolve (typically {@link CatalogInfo}).
* @since 1.0
* @see ResolvingCatalogFacadeDecorator
* @see ModificationProxy
*/
public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T> {
public class CatalogPropertyResolver {
private final Supplier<Catalog> catalog;
@ -65,7 +64,7 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
* @param catalog The {@link Catalog} to set on resolved objects; must not be null.
* @throws NullPointerException if {@code catalog} is null.
*/
public CatalogPropertyResolver(Catalog catalog) {
private CatalogPropertyResolver(Catalog catalog) {
Objects.requireNonNull(catalog, "Catalog must not be null");
this.catalog = () -> catalog;
}
@ -76,7 +75,7 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
* @param catalog A supplier providing the {@link Catalog}; must not be null.
* @throws NullPointerException if {@code catalog} is null.
*/
public CatalogPropertyResolver(@NonNull Supplier<Catalog> catalog) {
private CatalogPropertyResolver(@NonNull Supplier<Catalog> catalog) {
Objects.requireNonNull(catalog, "Catalog supplier must not be null");
this.catalog = catalog;
}
@ -99,8 +98,8 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
* @return A new {@link CatalogPropertyResolver} instance.
* @throws NullPointerException if {@code catalog} is null.
*/
public static <I extends Info> CatalogPropertyResolver<I> of(Catalog catalog) {
return new CatalogPropertyResolver<>(catalog);
public static <I extends Info> UnaryOperator<I> of(Catalog catalog) {
return new CatalogPropertyResolver(catalog)::apply;
}
/**
@ -111,19 +110,21 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
* @return A new {@link CatalogPropertyResolver} instance.
* @throws NullPointerException if {@code catalog} is null.
*/
public static <I extends Info> CatalogPropertyResolver<I> of(Supplier<Catalog> catalog) {
return new CatalogPropertyResolver<>(catalog);
public static <I extends Info> UnaryOperator<I> of(Supplier<Catalog> catalog) {
return new CatalogPropertyResolver(catalog)::apply;
}
/**
* Applies the resolver to an {@link Info} object, setting its catalog property if applicable.
*
* @param i The {@link Info} object to resolve; may be null.
* @param info The {@link Info} object to resolve; may be null.
* @return The resolved object with catalog set, or null if {@code i} is null.
*/
@Override
public T apply(T i) {
return resolve(i);
public <T> T apply(T info) {
if (info == null) {
return null;
}
return resolve(info);
}
/**
@ -134,24 +135,23 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
* {@link LayerGroupStyle}.
*
* @param <I> The type of {@link Info}.
* @param i The object to resolve; may be null.
* @param info The object to resolve; may be null.
* @return The resolved object, or null if {@code i} is null.
*/
@SuppressWarnings("unchecked")
private <I> I resolve(I i) {
i = null == i ? null : ModificationProxy.unwrap(i);
if (i instanceof StoreInfo store) {
private <I> I resolve(@NonNull I orig) {
I info = ModificationProxy.unwrap(orig);
if (info instanceof StoreInfo store) {
setCatalog(store);
} else if (i instanceof ResourceInfo resource) {
} else if (info instanceof ResourceInfo resource) {
setCatalog(resource);
} else if (i instanceof StyleInfo style) {
} else if (info instanceof StyleInfo style) {
setCatalog(style);
} else if (i instanceof PublishedInfo published) {
} else if (info instanceof PublishedInfo published) {
setCatalog(published);
} else if (i instanceof LayerGroupStyle lgs) {
} else if (info instanceof LayerGroupStyle lgs) {
setCatalog(lgs);
}
return i;
return orig;
}
/**
@ -159,21 +159,21 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
*
* @param list The collection to resolve; may be null (no action taken).
*/
private void resolve(Collection<?> list) {
private void apply(Collection<?> list) {
if (null != list) {
list.forEach(this::resolve);
list.forEach(this::apply);
}
}
/**
* Sets the catalog on a {@link PublishedInfo} object, dispatching to specific types.
*
* @param i The {@link PublishedInfo} to process; must not be null.
* @param published The {@link PublishedInfo} to process; must not be null.
*/
private void setCatalog(@NonNull PublishedInfo i) {
if (i instanceof LayerInfo li) {
private void setCatalog(@NonNull PublishedInfo published) {
if (published instanceof LayerInfo li) {
setCatalog(li);
} else if (i instanceof LayerGroupInfo lg) {
} else if (published instanceof LayerGroupInfo lg) {
setCatalog(lg);
}
}
@ -181,79 +181,79 @@ public class CatalogPropertyResolver<T extends Info> implements UnaryOperator<T>
/**
* Sets the catalog on a {@link LayerInfo} and resolves its nested references.
*
* @param i The {@link LayerInfo} to process; must not be null.
* @param layer The {@link LayerInfo} to process; must not be null.
*/
private void setCatalog(@NonNull LayerInfo i) {
resolve(i.getResource());
resolve(i.getDefaultStyle());
resolve(i.getStyles());
private void setCatalog(@NonNull LayerInfo layer) {
apply(layer.getResource());
apply(layer.getDefaultStyle());
apply(layer.getStyles());
}
/**
* Sets the catalog on a {@link LayerGroupInfo} and resolves its nested references.
*
* @param i The {@link LayerGroupInfo} to process; must not be null.
* @param layerGroup The {@link LayerGroupInfo} to process; must not be null.
*/
private void setCatalog(@NonNull LayerGroupInfo i) {
resolve(i.getRootLayer());
resolve(i.getRootLayerStyle());
resolve(i.getLayers());
resolve(i.getStyles());
resolve(i.getLayerGroupStyles());
private void setCatalog(@NonNull LayerGroupInfo layerGroup) {
apply(layerGroup.getRootLayer());
apply(layerGroup.getRootLayerStyle());
apply(layerGroup.getLayers());
apply(layerGroup.getStyles());
apply(layerGroup.getLayerGroupStyles());
}
/**
* Sets the catalog on a {@link LayerGroupStyle} and resolves its nested references.
*
* @param i The {@link LayerGroupStyle} to process; must not be null.
* @param lgStyle The {@link LayerGroupStyle} to process; must not be null.
*/
private void setCatalog(@NonNull LayerGroupStyle i) {
if (null != i.getLayers()) {
i.getLayers().forEach(this::setCatalog);
private void setCatalog(@NonNull LayerGroupStyle lgStyle) {
if (null != lgStyle.getLayers()) {
lgStyle.getLayers().forEach(this::apply);
}
if (null != i.getStyles()) {
i.getStyles().forEach(this::setCatalog);
if (null != lgStyle.getStyles()) {
lgStyle.getStyles().forEach(this::apply);
}
}
/**
* Sets the catalog on a {@link StoreInfo} if its a concrete implementation.
*
* @param i The {@link StoreInfo} to process; must not be null.
* @param store The {@link StoreInfo} to process; must not be null.
*/
private void setCatalog(@NonNull StoreInfo i) {
if (i instanceof StoreInfoImpl store) {
store.setCatalog(catalog());
private void setCatalog(@NonNull StoreInfo store) {
if (store instanceof StoreInfoImpl storeImpl) {
storeImpl.setCatalog(catalog());
}
}
/**
* Sets the catalog on a {@link ResourceInfo} and resolves its nested references.
*
* @param i The {@link ResourceInfo} to process; must not be null.
* @param resource The {@link ResourceInfo} to process; must not be null.
*/
private void setCatalog(@NonNull ResourceInfo i) {
i.setCatalog(catalog());
resolve(i.getStore());
if (i instanceof WMSLayerInfo wmsLayer) {
resolve(wmsLayer.getAllAvailableRemoteStyles());
private void setCatalog(@NonNull ResourceInfo resource) {
resource.setCatalog(catalog());
apply(resource.getStore());
if (resource instanceof WMSLayerInfo wmsLayer) {
apply(wmsLayer.getAllAvailableRemoteStyles());
}
}
/**
* Sets the catalog on a {@link StyleInfo} if its a concrete implementation.
*
* @param i The {@link StyleInfo} to process; must not be null.
* @param style The {@link StyleInfo} to process; must not be null.
*/
private void setCatalog(@NonNull StyleInfo i) {
if (i instanceof StyleInfoImpl style) {
private void setCatalog(@NonNull StyleInfo style) {
if (style instanceof StyleInfoImpl styleImpl) {
/*
* When the style is remote (null id), StyleInfoImpl.getSLD() will check for a null catalog and return null.
* Otherwise it'll call ResourcePool.getStyle(StyleInfo) and fail
*/
boolean isRemoteStyle = null == style.getId();
boolean isRemoteStyle = null == styleImpl.getId();
if (!isRemoteStyle) {
style.setCatalog(catalog());
styleImpl.setCatalog(catalog());
}
}
}

View File

@ -0,0 +1,358 @@
/* (c) 2025 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.catalog.plugin.resolving;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.function.UnaryOperator;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogInfo;
import org.geoserver.catalog.CatalogTestData;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.Info;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.DataStoreInfoImpl;
import org.geoserver.catalog.impl.FeatureTypeInfoImpl;
import org.geoserver.catalog.impl.LayerGroupInfoImpl;
import org.geoserver.catalog.impl.LayerGroupStyleImpl;
import org.geoserver.catalog.impl.LayerInfoImpl;
import org.geoserver.catalog.impl.ModificationProxy;
import org.geoserver.catalog.impl.ResolvingProxy;
import org.geoserver.catalog.impl.ResourceInfoImpl;
import org.geoserver.catalog.impl.StoreInfoImpl;
import org.geoserver.catalog.impl.StyleInfoImpl;
import org.geoserver.catalog.plugin.CatalogPlugin;
import org.geoserver.config.plugin.GeoServerImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CatalogPropertyResolverTest {
CatalogTestData testData;
GeoServerImpl geoServer;
Catalog catalog;
UnaryOperator<Info> resolver;
@BeforeEach
void setUp() {
catalog = new CatalogPlugin();
geoServer = new GeoServerImpl();
geoServer.setCatalog(catalog);
testData = CatalogTestData.initialized(() -> catalog, () -> geoServer).initCatalog();
resolver = CatalogPropertyResolver.of(catalog);
}
@Test
void testReturnsSame() {
assertThat(resolver.apply(null)).isNull();
testReturnsSame(testData.coverageA);
testReturnsSame(testData.dataStoreA);
testReturnsSame(testData.featureTypeA);
testReturnsSame(testData.layerFeatureTypeA);
testReturnsSame(testData.layerGroup1);
testReturnsSame(testData.namespaceA);
testReturnsSame(testData.workspaceA);
}
@Test
void testReturnsSameResolvingProxy() {
testReturnsSame(ResolvingProxy.create("test", StyleInfo.class));
testReturnsSame(ResolvingProxy.create("test", DataStoreInfo.class));
testReturnsSame(ResolvingProxy.create("test", CoverageStoreInfo.class));
testReturnsSame(ResolvingProxy.create("test", FeatureTypeInfo.class));
testReturnsSame(ResolvingProxy.create("test", CoverageInfo.class));
testReturnsSame(ResolvingProxy.create("test", LayerInfo.class));
testReturnsSame(ResolvingProxy.create("test", LayerGroupInfo.class));
testReturnsSame(ResolvingProxy.create("test", WorkspaceInfo.class));
testReturnsSame(ResolvingProxy.create("test", NamespaceInfo.class));
}
private void testReturnsSame(CatalogInfo info) {
CatalogInfo actual = ModificationProxy.unwrap(info);
CatalogInfo proxied = ModificationProxy.create(actual, CatalogInfo.class);
assertThat(resolver.apply(actual)).isSameAs(actual);
assertThat(resolver.apply(proxied)).isSameAs(proxied);
}
@Test
void storeInfo() {
StoreInfoImpl store = new DataStoreInfoImpl(null);
resolver.apply(store);
assertThat(store.getCatalog()).isSameAs(catalog);
store.setCatalog(null);
resolver.apply(ModificationProxy.create(store, StoreInfo.class));
assertThat(store.getCatalog()).isSameAs(catalog);
}
@Test
void resourceInfo() {
StoreInfoImpl store = new DataStoreInfoImpl(null);
ResourceInfoImpl resource = new FeatureTypeInfoImpl(null);
resource.setStore(store);
resolver.apply(resource);
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
resource.setCatalog(null);
store.setCatalog(null);
resource.setStore(ModificationProxy.create(store, DataStoreInfo.class));
resolver.apply(ModificationProxy.create(resource, FeatureTypeInfo.class));
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
}
@Test
void styleInfo() {
StyleInfoImpl style = new StyleInfoImpl(null);
style.setId("sid");
resolver.apply(style);
assertThat(style.getCatalog()).isSameAs(catalog);
style.setCatalog(null);
resolver.apply(ModificationProxy.create(style, StyleInfo.class));
assertThat(style.getCatalog()).isSameAs(catalog);
}
@Test
void styleInfoRemoveStyle() {
StyleInfoImpl style = new StyleInfoImpl(null);
style.setId(null); // this means it's a remote style
resolver.apply(style);
assertThat(style.getCatalog()).isNull();
resolver.apply(ModificationProxy.create(style, StyleInfo.class));
assertThat(style.getCatalog()).isNull();
}
@Test
void layerInfo() {
LayerInfoImpl layer = new LayerInfoImpl();
ResourceInfoImpl resource = new FeatureTypeInfoImpl(null);
StoreInfoImpl store = new DataStoreInfoImpl(null);
StyleInfoImpl defaultStyle = new StyleInfoImpl(null);
defaultStyle.setId("defaultStyle");
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl s2 = new StyleInfoImpl(null);
s2.setId("s2");
resource.setStore(store);
layer.setResource(resource);
layer.setDefaultStyle(defaultStyle);
layer.getStyles().add(s1);
layer.getStyles().add(s2);
resolver.apply(layer);
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
resource.setStore(ModificationProxy.create(store, DataStoreInfo.class));
layer.setResource(ModificationProxy.create(resource, FeatureTypeInfo.class));
layer.setDefaultStyle(ModificationProxy.create(defaultStyle, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s1, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s2, StyleInfo.class));
resolver.apply(ModificationProxy.create(layer, LayerInfo.class));
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
}
@Test
void layerGroupInfoLayers() {
LayerGroupInfoImpl layerGroup = new LayerGroupInfoImpl();
LayerInfoImpl layer = new LayerInfoImpl();
ResourceInfoImpl resource = new FeatureTypeInfoImpl(null);
StoreInfoImpl store = new DataStoreInfoImpl(null);
StyleInfoImpl defaultStyle = new StyleInfoImpl(null);
defaultStyle.setId("defaultStyle");
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl s2 = new StyleInfoImpl(null);
s2.setId("s2");
resource.setStore(store);
layer.setResource(resource);
layer.setDefaultStyle(defaultStyle);
layer.getStyles().add(s1);
layer.getStyles().add(s2);
layerGroup.getLayers().add(layer);
resolver.apply(layerGroup);
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
resource.setStore(ModificationProxy.create(store, DataStoreInfo.class));
layer.setResource(ModificationProxy.create(resource, FeatureTypeInfo.class));
layer.setDefaultStyle(ModificationProxy.create(defaultStyle, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s1, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s2, StyleInfo.class));
resolver.apply(ModificationProxy.create(layerGroup, LayerGroupInfo.class));
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
}
@Test
void layerGroupInfoStyles() {
LayerGroupInfoImpl layerGroup = new LayerGroupInfoImpl();
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl remoteStyle = new StyleInfoImpl(null);
remoteStyle.setId(null);
StyleInfoImpl s2 = new StyleInfoImpl(null);
s2.setId("s2");
layerGroup.getStyles().add(s1);
layerGroup.getStyles().add(remoteStyle);
layerGroup.getStyles().add(s2);
layerGroup.getStyles().add(null);
resolver.apply(layerGroup);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(remoteStyle.getCatalog()).isNull();
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(layerGroup.getStyles().get(3)).isNull();
s1.setCatalog(null);
s2.setCatalog(null);
layerGroup.getStyles().clear();
layerGroup.getStyles().add(null);
layerGroup.getStyles().add(ModificationProxy.create(s1, StyleInfo.class));
layerGroup.getStyles().add(ModificationProxy.create(remoteStyle, StyleInfo.class));
layerGroup.getStyles().add(ModificationProxy.create(s2, StyleInfo.class));
resolver.apply(ModificationProxy.create(layerGroup, LayerGroupInfo.class));
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(remoteStyle.getCatalog()).isNull();
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(layerGroup.getStyles().get(0)).isNull();
}
@Test
void layerGroupInfoRootLayer() {
LayerGroupInfoImpl layerGroup = new LayerGroupInfoImpl();
LayerInfoImpl layer = new LayerInfoImpl();
ResourceInfoImpl resource = new FeatureTypeInfoImpl(null);
StoreInfoImpl store = new DataStoreInfoImpl(null);
StyleInfoImpl defaultStyle = new StyleInfoImpl(null);
defaultStyle.setId("defaultStyle");
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl s2 = new StyleInfoImpl(null);
s2.setId("s2");
resource.setStore(store);
layer.setResource(resource);
layer.setDefaultStyle(defaultStyle);
layer.getStyles().add(s1);
layer.getStyles().add(s2);
layerGroup.setRootLayer(layer);
resolver.apply(layerGroup);
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
resource.setStore(ModificationProxy.create(store, DataStoreInfo.class));
layer.setResource(ModificationProxy.create(resource, FeatureTypeInfo.class));
layer.setDefaultStyle(ModificationProxy.create(defaultStyle, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s1, StyleInfo.class));
layer.getStyles().add(ModificationProxy.create(s2, StyleInfo.class));
resolver.apply(ModificationProxy.create(layerGroup, LayerGroupInfo.class));
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(s2.getCatalog()).isSameAs(catalog);
}
@Test
void layerGroupInfoRootLayerStyle() {
LayerGroupInfoImpl layerGroup = new LayerGroupInfoImpl();
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl remoteStyle = new StyleInfoImpl(null);
remoteStyle.setId(null);
layerGroup.setRootLayerStyle(s1);
resolver.apply(layerGroup);
assertThat(s1.getCatalog()).isSameAs(catalog);
s1.setCatalog(null);
resolver.apply(ModificationProxy.create(layerGroup, LayerGroupInfo.class));
assertThat(s1.getCatalog()).isSameAs(catalog);
layerGroup.setRootLayerStyle(remoteStyle);
resolver.apply(layerGroup);
assertThat(remoteStyle.getCatalog()).isNull();
}
@Test
void layerGroupLayerGroupStyles() {
LayerInfoImpl layer = new LayerInfoImpl();
ResourceInfoImpl resource = new FeatureTypeInfoImpl(null);
StoreInfoImpl store = new DataStoreInfoImpl(null);
StyleInfoImpl defaultStyle = new StyleInfoImpl(null);
defaultStyle.setId("defaultStyle");
StyleInfoImpl s1 = new StyleInfoImpl(null);
s1.setId("s1");
StyleInfoImpl remoteStyle = new StyleInfoImpl(null);
remoteStyle.setId(null);
resource.setStore(store);
layer.setResource(resource);
layer.setDefaultStyle(defaultStyle);
LayerGroupStyleImpl lgStyle = new LayerGroupStyleImpl();
lgStyle.getStyles().add(remoteStyle);
lgStyle.getLayers().add(null);
lgStyle.getLayers().add(layer);
lgStyle.getStyles().add(s1);
lgStyle.getLayers().add(null);
lgStyle.getStyles().add(null);
LayerGroupInfoImpl layerGroup = new LayerGroupInfoImpl();
layerGroup.getLayerGroupStyles().add(null);
layerGroup.getLayerGroupStyles().add(lgStyle);
resolver.apply(layerGroup);
assertThat(resource.getCatalog()).isSameAs(catalog);
assertThat(store.getCatalog()).isSameAs(catalog);
assertThat(defaultStyle.getCatalog()).isSameAs(catalog);
assertThat(s1.getCatalog()).isSameAs(catalog);
assertThat(remoteStyle.getCatalog()).isNull();
}
}