Skip to content

Commit

Permalink
Add test verifying partial template works; Extract accessAwareFieldVa…
Browse files Browse the repository at this point in the history
…lueResolver; Add test verifying priority fo values extracted from object
  • Loading branch information
WouterBaeyens committed Sep 26, 2024
1 parent 76d3964 commit 998cdeb
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import lombok.Setter;
import org.openapitools.codegen.api.AbstractTemplatingEngineAdapter;
import org.openapitools.codegen.api.TemplatingExecutor;
import org.openapitools.codegen.templating.handlebars.AccessAwareFieldValueResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -45,7 +46,7 @@
import java.util.stream.Collectors;

public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
final Logger LOGGER = LoggerFactory.getLogger(HandlebarsEngineAdapter.class);
final Logger LOGGER = LoggerFactory.getLogger(HandlebarsEngineAdapter.class);
private final String[] extensions = {"handlebars", "hbs"};

// We use this as a simple lookup for valid file name extensions. This adapter will inspect .mustache (built-in) and infer the relevant handlebars filename
Expand Down Expand Up @@ -73,36 +74,13 @@ public TemplateSource sourceAt(String location) {
}
};

// $ref: https://github.com/jknack/handlebars.java/issues/917
var accessAwareFieldValueResolverInstance = new FieldValueResolver() {
@Override
protected Set<FieldWrapper> members(
Class<?> clazz) {
var members = super.members(clazz);
return members.stream()
.filter(fw -> isValidField(fw))
.collect(Collectors.toSet());
}

boolean isValidField(
FieldWrapper fw) {
if (fw instanceof AccessibleObject) {
if (isUseSetAccessible(fw)) {
return true;
}
return false;
}
return true;
}
};

Context context = Context
.newBuilder(bundle)
.resolver(
MapValueResolver.INSTANCE,
JavaBeanValueResolver.INSTANCE,
accessAwareFieldValueResolverInstance,
MethodValueResolver.INSTANCE)
MethodValueResolver.INSTANCE,
AccessAwareFieldValueResolver.INSTANCE)
.build();

Handlebars handlebars = new Handlebars(loader);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.openapitools.codegen.templating.handlebars;

import com.github.jknack.handlebars.context.FieldValueResolver;

import java.lang.reflect.AccessibleObject;
import java.util.Set;
import java.util.stream.Collectors;

// $ref: https://github.com/jknack/handlebars.java/issues/917
public class AccessAwareFieldValueResolver extends FieldValueResolver {

public static final AccessAwareFieldValueResolver INSTANCE = new AccessAwareFieldValueResolver();

@Override
protected Set<FieldValueResolver.FieldWrapper> members(Class<?> clazz) {
var members = super.members(clazz);
return members.stream()
.filter(this::isValidField)
.collect(Collectors.toSet());
}

boolean isValidField(FieldWrapper fw) {
if (fw instanceof AccessibleObject) {
return isUseSetAccessible(fw);
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.openapitools.codegen.templating;

import org.mockito.Mockito;
import org.openapitools.codegen.api.TemplatingExecutor;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import static org.testng.Assert.*;
import java.io.IOException;
import java.util.Map;

import static org.testng.Assert.assertEquals;

public class HandlebarsEngineAdapterTest {
@Test(dataProvider = "handlesFileExpectations")
Expand Down Expand Up @@ -33,4 +38,73 @@ public Object[][] handlesFileExpectations() {
{"README.md", false, "Should not attempt to handle non-handlebars extensions (other than mustache)"}
};
}

@Test(description = "verify https://github.com/jknack/handlebars.java/issues/940#issue-1111612043 is fixed")
public void testHandlePartialTemplate() throws IOException {
// Given
HandlebarsEngineAdapter adapter = new HandlebarsEngineAdapter();
TemplatingExecutor executorMock = Mockito.mock(TemplatingExecutor.class);
Mockito.when(executorMock.getFullTemplateContents("outerTemplate.hbs")).thenReturn("Contents: {{>innerTemplate}}");
Mockito.when(executorMock.getFullTemplateContents("innerTemplate.hbs")).thenReturn("'Specific contents'");

// When
String generatedFile = adapter.compileTemplate(executorMock, Map.of(), "outerTemplate.hbs");

// Then
assertEquals(generatedFile, "Contents: 'Specific contents'");
}

@Test(description = "should prioritize public getters over breaking encapsulation")
public void testResolverPriority() throws IOException {
// Given
HandlebarsEngineAdapter adapter = new HandlebarsEngineAdapter();
TemplatingExecutor executorMock = Mockito.mock(TemplatingExecutor.class);
Mockito.when(executorMock.getFullTemplateContents("outerTemplate.hbs")).thenReturn(
"Contents: {{#propertyObj}}\n" +
" public getter: {{valueMethodAndBean}}\n" +
" public method: {{valueAndMethod}}\n" +
" private property: {{valueOnly}}{{/propertyObj}}");

Map<String, Object> bundle = Map.of("propertyObj", new PropertyObject());

// When
String generatedFile = adapter.compileTemplate(executorMock, bundle, "outerTemplate.hbs");

// Then
assertEquals(generatedFile, "Contents: \n" +
" public getter: get_raw_data1_formatted\n" +
" public method: raw_data2_formatted\n" +
" private property: raw_data3");
}

static class PropertyObject {
/**
* getter-exposed
*/
private final String valueMethodAndBean = "raw_data1";

public String valueMethodAndBean() {
return valueMethodAndBean + "_formatted";
}

public String getValueMethodAndBean() {
return "get_" + valueMethodAndBean();
}

/**
* method-exposed
*/
private final String valueAndMethod = "raw_data2";

public String valueAndMethod() {
return valueAndMethod + "_formatted";
}

/**
* private
* note: ideally we long-term move towards respecting encapsulation where possible
*/
@SuppressWarnings({"unused", "java:S1068"}) // this private value is still read by our HandleBars engine
private final String valueOnly = "raw_data3";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private void evaluate(HashMap<String, Object> data, String template, String expe
Context context = Context
.newBuilder(data)
.resolver(
FieldValueResolver.INSTANCE)
AccessAwareFieldValueResolver.INSTANCE)
.build();

Template tmpl = handlebars.compileInline(template);
Expand Down

0 comments on commit 998cdeb

Please sign in to comment.