All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.render.RenderableDecorator Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2014 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 ratpack.render;

import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import ratpack.func.Action;
import ratpack.handling.Context;
import ratpack.registry.RegistrySpec;

import java.util.function.BiFunction;

/**
 * Decorates an object before it is {@link Context#render(Object) rendered}.
 * 

* While this type is called renderable decorator, it is not restricted to decorating {@link Renderable} implementations * but is used to decorate all types of objects to be rendered. *

* Renderable decorators are able to decorate/transform objects to be rendered. * That is, they effectively sit between the call to {@link Context#render(Object)} and {@link Renderer#render(Context, Object)} of the target renderer. * All of the decorators that are type compatible with the object to be rendered are invoked cumulatively in the order that they are returned from the context registry. *

* It is not required, but generally advisable for decorators to return a new object instead of mutating the object they receive. *

{@code
 * import ratpack.test.embed.EmbeddedApp;
 * import ratpack.render.Renderer;
 * import ratpack.render.RenderableDecorator;
 *
 * import static org.junit.Assert.*;
 *
 * public class Example {
 *   public static void main(String... args) {
 *     EmbeddedApp.fromChain(chain -> chain
 *       .register(registry -> registry
 *         .add(Renderer.of(Integer.class, (ctx, i) -> ctx.render(i.toString())))
 *         .add(RenderableDecorator.of(Integer.class, (ctx, i) -> i * 2))
 *         .add(RenderableDecorator.of(Integer.class, (ctx, i) -> i * 2))
 *       )
 *       .get(ctx -> ctx.render(1))
 *     ).test(httpClient ->
 *       assertEquals("4", httpClient.getText())
 *     );
 *   }
 * }
 * }
*

* Such decorators are often used to augment the “model” being given to a template rendering engine to include implicit services and so forth. *

* Note that decorators are selected based on the exact runtime type of the object being rendered, that is based on its {@link Object#getClass()}. * As such, decorators must advertise to decorate concrete types as opposed to interfaces or super classes. * A decorator effectively cannot change the type of the object-to-render. * * @param the type of object-to-render that this decorator decorates */ public interface RenderableDecorator { /** * Creates a type token for a decorator of objects of the given type. * * @param type the object-to-render type * @param the object-to-render type * @return a type token for a decorator of objects of the given type */ static TypeToken> typeOf(Class type) { return new TypeToken>(type) {}.where(new TypeParameter() {}, type); } /** * The type of objects that this decorator decorates. * * @return the type of objects that this decorator decorates */ Class getType(); /** * Decorates the given object on its way to being rendered. *

* Implementations may either mutate the object and return it, or return an entirely new object. * * @param context the request context * @param object the object-to-render * @return the decorated object */ T decorate(Context context, T object); /** * Creates a renderable decorator implementation from the given arguments. * * @param type the type of object-to-render to decorate * @param impl the implementation of the {@link #decorate(Context, Object)} method * @param the type of object-to-render to decorate * @return a renderable decorator implementation */ static RenderableDecorator of(Class type, BiFunction impl) { return new RenderableDecorator() { @Override public Class getType() { return type; } @Override public T decorate(Context context, T object) { return impl.apply(context, object); } }; } /** * A registration action, typically used with {@link RegistrySpec#with(Action)}. *

* Registers this object with the type {@code RenderableDecorator} (where {@code T} is the value of {@link #getType()}), not its concrete type. * * @return a registration action */ default Action register() { return (registrySpec) -> registrySpec.add(typeOf(getType()), this); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy