Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spring-webflux compatibility to handlebars-springmvc (#642) #647

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions handlebars-springmvc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@
<artifactId>spring-webmvc</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package com.github.jknack.handlebars.springmvc;

import static com.github.jknack.handlebars.springmvc.SpringUtils.createI18nSource;
import static java.util.Objects.requireNonNull;

import java.io.File;
Expand All @@ -26,10 +27,7 @@
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
Expand Down Expand Up @@ -264,33 +262,6 @@ public void afterPropertiesSet() {
handlebars.setCharset(charset);
}

/**
* Creates a new i18n source.
*
* @param context The application context.
* @return A new i18n source.
*/
private static I18nSource createI18nSource(final ApplicationContext context) {
return new I18nSource() {
@Override
public String message(final String key, final Locale locale, final Object... args) {
return context.getMessage(key, args, locale);
}

@Override
public String[] keys(final String basename, final Locale locale) {
ResourceBundle bundle = ResourceBundle.getBundle(basename, locale);
Enumeration<String> keys = bundle.getKeys();
List<String> result = new ArrayList<String>();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
result.add(key);
}
return result.toArray(new String[result.size()]);
}
};
}

/**
* Creates a new {@link Handlebars} object using the parameter {@link TemplateLoader}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* 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.github.jknack.handlebars.springmvc;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import org.springframework.context.ApplicationContext;

import com.github.jknack.handlebars.helper.I18nSource;

/**
* @author OhChang Kwon([email protected])
*/
public final class SpringUtils {
/** private constructor for Util class. */
private SpringUtils() {
}

/**
* Creates a new i18n source.
*
* @param context The application context.
* @return A new i18n source.
*/
public static I18nSource createI18nSource(final ApplicationContext context) {
return new I18nSource() {
@Override
public String message(final String key, final Locale locale, final Object... args) {
return context.getMessage(key, args, locale);
}

@Override
public String[] keys(final String basename, final Locale locale) {
ResourceBundle bundle = ResourceBundle.getBundle(basename, locale);
Enumeration<String> keys = bundle.getKeys();
List<String> result = new ArrayList<>();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
result.add(key);
}
return result.toArray(new String[0]);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* 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.github.jknack.handlebars.springmvc.webflux;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.MediaType;
import org.springframework.util.MimeType;
import org.springframework.web.reactive.result.view.AbstractUrlBasedView;
import org.springframework.web.server.ServerWebExchange;

import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.ValueResolver;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
* A handlebars reactive view implementation.
*
* @author OhChang Kwon([email protected])
*/
public class ReactiveHandlebarsView extends AbstractUrlBasedView {

/**
* The compiled template.
*/
private Template template;

/**
* The value's resolvers.
*/
private ValueResolver[] valueResolvers;

/**
* Set the value resolvers.
*
* @param valueResolvers The value resolvers. Required.
* @throws IllegalArgumentException If the value resolvers are null or empty.
*/
void setValueResolvers(final ValueResolver... valueResolvers) {
if (ArrayUtils.isEmpty(valueResolvers)) {
throw new IllegalArgumentException("At least one value-resolver must be present.");
} else {
this.valueResolvers = valueResolvers;
}
}

/**
* @return The underlying template for this view.
*/
public Template getTemplate() {
return this.template;
}

/**
* Set the compiled template.
*
* @param template The compiled template. Required.
*/
void setTemplate(final Template template) {
this.template = Objects.requireNonNull(template,
"A handlebars template is required.");
}

/**
* {@inheritDoc}
*/
@Override
public boolean checkResourceExists(final Locale locale) {
return template != null;
}

/**
* {@inheritDoc}
*/
@Override
protected Mono<Void> renderInternal(final Map<String, Object> renderAttributes,
final MediaType contentType,
final ServerWebExchange exchange) {
final Context context = Context.newBuilder(renderAttributes)
.resolver(valueResolvers)
.build();

final DataBuffer dataBuffer = exchange.getResponse().bufferFactory().allocateBuffer();
final Charset charset = Optional.ofNullable(contentType).map(MimeType::getCharset)
.orElse(getDefaultCharset());

try (final Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset)) {
template.apply(context, writer);
writer.flush();
} catch (IOException e) {
DataBufferUtils.release(dataBuffer);
return Mono.error(e);
} finally {
context.destroy();
}

return exchange.getResponse().writeWith(Flux.just(dataBuffer));
}
}
Loading