com.foreach.across.modules.web.ui.ViewElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of across-web Show documentation
Show all versions of across-web Show documentation
Across is a Java framework that aims to facilitate module based development for Java (web) applications.
It builds heavily on Spring framework and allows defining a module consisting of a number of classes and
configuration files. Every module defines its own Spring application context and can share one or more beans
with other modules.
/*
* Copyright 2019 the original author or authors
*
* 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.foreach.across.modules.web.ui;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Represents a {@link ViewElement} in its most simple form. In a web context this is almost certainly
* a HTML node or collection thereof.
*
* @see MutableViewElement
*/
public interface ViewElement
{
/**
* A ViewElement can have an internal name that identifies it within a
* {@link com.foreach.across.modules.web.ui.elements.ContainerViewElement}. A name is optional but when given,
* is preferably unique within its container as most operations work on the first element with a specific name.
*
* @return Internal name of this element, can be null.
* @see com.foreach.across.modules.web.ui.elements.support.ContainerViewElementUtils
*/
String getName();
/**
* @return Type id of this view element.
*/
String getElementType();
/**
* @return Custom template to use when rendering this view element.
*/
String getCustomTemplate();
/**
* Execute one or more setter functions.
*
* @param setters to execute
* @return self
*/
default ViewElement set( WitherSetter... setters ) {
with( this ).set( setters );
return this;
}
/**
* Execute one or more remover functions. A remover is defined as a separate interface
* so implementations can both implement setter and remover at the same time.
*
* @param functions to execute
* @return self
*/
default ViewElement remove( WitherRemover... functions ) {
with( this ).remove( functions );
return this;
}
/**
* Check if the element matches the predicate given.
* Note there is no compiler type-safety on this method, predicate implementations should do the type checking.
* See also {@link #predicateFor(Class, Predicate)} for a helper function to create a typed predicate inline.
*
* @param predicate to test
* @return predicate outcome
*/
@SuppressWarnings("unchecked")
default boolean matches( @NonNull Predicate predicate ) {
return predicate.test( this );
}
/**
* Get a value from the element. Use {@link WitherGetter#as(Class)} for compile time typing.
* Note that runtime type casting execptions will occur when using the wrong type.
*
* @param function that returns the value
* @param type of the expected return value
* @return value
*/
default U get( WitherGetter, U> function ) {
return with( this ).get( function );
}
/**
* Create a {@link Wither} wrapper for an element, which allows for a more
* descriptive, fluent configuration approach by using pre-defined lambdas.
*
* @param element to create a wrapper for
* @param type of the element
* @return wither
*/
static Wither with( @NonNull U element ) {
return new Wither<>( element );
}
/**
* A wrapper for any type of {@link ViewElement} which allows the use of separate
* functions to perform the actions. Uses 3 separate functional interfaces to perform
* typical actions and convey meaning (get, set, remove).
*
* The main purpose of the wither approach is to allow a library of functions to be
* defined that allow a more descriptive and fluent approach of configuration elements.
* Using separate functions increases testability and removes the need for a complex class hierarchy.
*
* Default functions are available for typical html node actions.
*
* Because of limitations with generics, the wither does not define a type on its parameter interfaces.
* This means that the function implementations should do type checking at runtime where appropriate,
* or runtime class cast exceptions will be thrown.
*
* @param type of the view element
* @see WitherRemover function that is expected to remove one or more settings from the element (eg. attributes)
* @see WitherGetter function to fetch a value, allows for typing the result
* @see WitherSetter function that is expected to set one or more values on the element
* @see MutableViewElement.Functions
*/
@RequiredArgsConstructor
class Wither
{
private final T element;
/**
* Execute one or more setter functions.
*
* @param setters to execute
* @return self
*/
@SuppressWarnings("unchecked")
public Wither set( WitherSetter... setters ) {
Stream.of( setters ).forEach( c -> c.applyTo( element ) );
return this;
}
/**
* Allows for a specifically typed generic consumer to be passed or defined.
*
* @param consumer to execute
* @return self
*/
public Wither apply( Consumer super T> consumer ) {
consumer.accept( element );
return this;
}
/**
* Execute one or more remover functions. A remover is defined as a separate interface
* so implementations can both implement setter and remover at the same time.
*
* @param functions to execute
* @return self
*/
@SuppressWarnings("unchecked")
public Wither remove( WitherRemover... functions ) {
Stream.of( functions ).forEach( r -> r.removeFrom( element ) );
return this;
}
/**
* Get a value from the element. Use {@link WitherGetter#as(Class)} for compile time typing.
* Note that runtime type casting execptions will occur when using the wrong type.
*
* @param function that returns the value
* @param type of the expected return value
* @return value
*/
@SuppressWarnings("unchecked")
public U get( WitherGetter, U> function ) {
return (U) ( (WitherGetter) function ).getValueFrom( element );
}
public T get() {
return element;
}
}
/**
* Function that modifies a view element by setting or adding values.
* Typical example: setting an attribute value.
*
* @param type of the view element
*/
@FunctionalInterface
interface WitherSetter
{
void applyTo( T target );
}
/**
* Function that modifies a view element by removing values.
* Typical example: removing an attribute.
* See also {@link MutableViewElement.Functions#remove(WitherRemover[])} to
* convert a remover functions into {@link WitherSetter}.
*
* @param type of the view element
*/
@FunctionalInterface
interface WitherRemover
{
void removeFrom( T target );
}
/**
* Function that fetches a value from a view element and optionally returns
* it as a specific type for compile time checking.
* Typical example: getting an attribute value.
*
* @param type of the view element
*/
@FunctionalInterface
interface WitherGetter
{
U getValueFrom( T target );
/**
* Cast the return value as a specific type, to avoid explicit casting in consumer code.
*/
@SuppressWarnings({ "unchecked", "unused" })
default WitherGetter as( Class clazz ) {
return (WitherGetter) this;
}
}
/**
* Short-hand for creating an anonymous typed predicate, can be used to inline type predicate creation.
*/
static Predicate predicateFor( Class elementType, Predicate predicate ) {
return predicate;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy