mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
Qute - add some javadoc to public API
- minor optimization in EvaluatorImpl - added float and double literal support + tests
This commit is contained in:
@@ -5,30 +5,44 @@ import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Template engine configuration.
|
||||
* Represents a central point for template management. It has a dedicated configuration and is able to cache the
|
||||
* template definitions.
|
||||
*/
|
||||
public interface Engine {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a new builder instance
|
||||
*/
|
||||
static EngineBuilder builder() {
|
||||
return new EngineBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the template contents.
|
||||
* <p>
|
||||
* Note that this method always returns a new {@link Template} instance.
|
||||
*
|
||||
* @param content
|
||||
* @return the template
|
||||
* @see Engine#getTemplate(String)
|
||||
*/
|
||||
default Template parse(String content) {
|
||||
return parse(content, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the template contents with the specified variant.
|
||||
* <p>
|
||||
* Note that this method always returns a new {@link Template} instance.
|
||||
*
|
||||
* @param content
|
||||
* @param variant
|
||||
* @return the template
|
||||
* @see Engine#getTemplate(String)
|
||||
*/
|
||||
public Template parse(String content, Variant variant);
|
||||
|
||||
public SectionHelperFactory<?> getSectionHelperFactory(String name);
|
||||
|
||||
public Map<String, SectionHelperFactory<?>> getSectionHelperFactories();
|
||||
|
||||
public List<ValueResolver> getValueResolvers();
|
||||
|
||||
public List<NamespaceResolver> getNamespaceResolvers();
|
||||
|
||||
public Evaluator getEvaluator();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return an immutable list of result mappers
|
||||
@@ -44,7 +58,7 @@ public interface Engine {
|
||||
public Template putTemplate(String id, Template template);
|
||||
|
||||
/**
|
||||
* Obtain a compiled template for the given id. The template could be registered using
|
||||
* Obtain a template for the given identifier. The template could be registered using
|
||||
* {@link #putTemplate(String, Template)} or loaded by a template locator.
|
||||
*
|
||||
* @param id
|
||||
@@ -65,4 +79,14 @@ public interface Engine {
|
||||
*/
|
||||
public void removeTemplates(Predicate<String> test);
|
||||
|
||||
public SectionHelperFactory<?> getSectionHelperFactory(String name);
|
||||
|
||||
public Map<String, SectionHelperFactory<?>> getSectionHelperFactories();
|
||||
|
||||
public List<ValueResolver> getValueResolvers();
|
||||
|
||||
public List<NamespaceResolver> getNamespaceResolvers();
|
||||
|
||||
public Evaluator getEvaluator();
|
||||
|
||||
}
|
||||
|
||||
@@ -93,6 +93,12 @@ public final class EngineBuilder {
|
||||
}
|
||||
|
||||
public EngineBuilder addNamespaceResolver(NamespaceResolver resolver) {
|
||||
for (NamespaceResolver namespaceResolver : namespaceResolvers) {
|
||||
if (namespaceResolver.getNamespace().equals(resolver.getNamespace())) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Namespace %s is already handled by %s", resolver.getNamespace()));
|
||||
}
|
||||
}
|
||||
this.namespaceResolvers.add(resolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
* Each part of an {@link Expression} is evaluated with a new context.
|
||||
* Evaluation context of a specific part of an {@link Expression}.
|
||||
*
|
||||
* @see Expression#parts
|
||||
*/
|
||||
public interface EvalContext {
|
||||
|
||||
@@ -29,8 +31,20 @@ public interface EvalContext {
|
||||
*/
|
||||
List<String> getParams();
|
||||
|
||||
/**
|
||||
* Parse and evaluate the given expression using the relevant {@link ResolutionContext}
|
||||
*
|
||||
* @param expression
|
||||
* @return the result
|
||||
*/
|
||||
CompletionStage<Object> evaluate(String expression);
|
||||
|
||||
/**
|
||||
* Evaluate the given expression using the relevant {@link ResolutionContext}.
|
||||
*
|
||||
* @param expression
|
||||
* @return the result
|
||||
*/
|
||||
CompletionStage<Object> evaluate(Expression expression);
|
||||
|
||||
}
|
||||
@@ -66,14 +66,21 @@ class EvaluatorImpl implements Evaluator {
|
||||
|
||||
private CompletionStage<Object> resolveReference(boolean tryParent, Object ref, Iterator<String> parts,
|
||||
ResolutionContext resolutionContext) {
|
||||
return resolve(new EvalContextImpl(tryParent, ref, parts.next(), resolutionContext), resolvers.iterator())
|
||||
.thenCompose(r -> {
|
||||
if (parts.hasNext()) {
|
||||
return resolveReference(tryParent, r, parts, resolutionContext);
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(r);
|
||||
}
|
||||
});
|
||||
String part = parts.next();
|
||||
EvalContextImpl evalContext = new EvalContextImpl(tryParent, ref, part, resolutionContext);
|
||||
if (!parts.hasNext()) {
|
||||
// The last part - no need to compose
|
||||
return resolve(evalContext, resolvers.iterator());
|
||||
} else {
|
||||
return resolve(evalContext, resolvers.iterator())
|
||||
.thenCompose(r -> {
|
||||
if (parts.hasNext()) {
|
||||
return resolveReference(tryParent, r, parts, resolutionContext);
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(r);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private CompletionStage<Object> resolve(EvalContextImpl evalContext, Iterator<ValueResolver> resolvers) {
|
||||
|
||||
@@ -12,6 +12,12 @@ import java.util.concurrent.ExecutionException;
|
||||
/**
|
||||
* Represents a value expression. It could be a literal such as {@code 'foo'}. It could have a namespace such as {@code data}
|
||||
* for {@code data:name}. It could have several parts such as {@code item} and {@code name} for {@code item.name}.
|
||||
* <p>
|
||||
* An expression may have a "type check information" attached. The string has a form {@code [TYPE_INFO]<SECTION_HINT>.foo.baz}
|
||||
* where TYPE_INFO represent the fully qualified type name (including type parameters) and SECTION_HINT represents an optional
|
||||
* hint set by the corresponding section helper. For example the expression {@code foo.name} may have the following type check
|
||||
* info: {@code [org.acme.Foo].name} and the expression {@code it.name} may have
|
||||
* {@code [java.util.List<org.acme.Label>]<for-element>.name}.
|
||||
*
|
||||
* @see Evaluator
|
||||
*/
|
||||
|
||||
@@ -8,9 +8,10 @@ class LiteralSupport {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LiteralSupport.class);
|
||||
|
||||
static final Pattern INTEGER_LITERAL_PATTERN = Pattern.compile("(\\+|-)?\\d{1,10}");
|
||||
|
||||
static final Pattern LONG_LITERAL_PATTERN = Pattern.compile("(\\+|-)?\\d{1,19}(L|l)");
|
||||
static final Pattern INTEGER_LITERAL_PATTERN = Pattern.compile("[-+]?\\d{1,10}");
|
||||
static final Pattern LONG_LITERAL_PATTERN = Pattern.compile("[-+]?\\d{1,19}(L|l)");
|
||||
static final Pattern DOUBLE_LITERAL_PATTERN = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+(d|D)");
|
||||
static final Pattern FLOAT_LITERAL_PATTERN = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+(f|F)");
|
||||
|
||||
static Object getLiteral(String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
@@ -25,18 +26,37 @@ class LiteralSupport {
|
||||
literal = Boolean.FALSE;
|
||||
} else if (value.equals("null")) {
|
||||
literal = null;
|
||||
} else if (INTEGER_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse integer literal: " + value, e);
|
||||
}
|
||||
} else if (LONG_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Long
|
||||
.parseLong(value.substring(0, value.length() - 1));
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse long literal: " + value, e);
|
||||
} else {
|
||||
char firstChar = value.charAt(0);
|
||||
if (Character.isDigit(firstChar) || firstChar == '-' || firstChar == '+') {
|
||||
if (INTEGER_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse integer literal: " + value, e);
|
||||
}
|
||||
} else if (LONG_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Long
|
||||
.parseLong(value.substring(0, value.length() - 1));
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse long literal: " + value, e);
|
||||
}
|
||||
} else if (DOUBLE_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Double
|
||||
.parseDouble(value.substring(0, value.length() - 1));
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse double literal: " + value, e);
|
||||
}
|
||||
} else if (FLOAT_LITERAL_PATTERN.matcher(value).matches()) {
|
||||
try {
|
||||
literal = Float
|
||||
.parseFloat(value.substring(0, value.length() - 1));
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Unable to parse float literal: " + value, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return literal;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
/**
|
||||
* Maps keys to values in a similar way to {@link java.util.Map}. The difference is that it could be stateless, ie. the lookup
|
||||
* may be performed dynamically.
|
||||
*
|
||||
* @see ValueResolvers#mapperResolver()
|
||||
*/
|
||||
public interface Mapper {
|
||||
|
||||
Object get(String key);
|
||||
|
||||
@@ -4,6 +4,9 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A result node backed by an array of result nodes.
|
||||
*/
|
||||
public class MultiResultNode implements ResultNode {
|
||||
|
||||
private final ResultNode[] results;
|
||||
|
||||
@@ -5,11 +5,20 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
|
||||
/*
|
||||
* Namespace resolver.
|
||||
/**
|
||||
* Namespace resolvers are used to find the current context object for an expression that starts with a namespace declaration.
|
||||
* <p>
|
||||
* For example the expression {@code data:colors} declares a namespace {@code data}.
|
||||
*
|
||||
* @see EngineBuilder#addNamespaceResolver(NamespaceResolver)
|
||||
*/
|
||||
public interface NamespaceResolver extends Resolver {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param namespace
|
||||
* @return a new builder instance
|
||||
*/
|
||||
static Builder builder(String namespace) {
|
||||
return new Builder(namespace);
|
||||
}
|
||||
@@ -21,10 +30,7 @@ public interface NamespaceResolver extends Resolver {
|
||||
*/
|
||||
String getNamespace();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Builder {
|
||||
final class Builder {
|
||||
|
||||
private final String namespace;
|
||||
private Function<EvalContext, CompletionStage<Object>> resolve;
|
||||
|
||||
@@ -45,6 +45,8 @@ class Parser implements Function<String, Expression> {
|
||||
static final char START_COMPOSITE_PARAM = '(';
|
||||
static final char END_COMPOSITE_PARAM = ')';
|
||||
|
||||
static final String TYPE_CHECK_NAMESPACE = "[" + Expressions.TYPECHECK_NAMESPACE_PLACEHOLDER + "].";
|
||||
|
||||
private StringBuilder buffer;
|
||||
private State state;
|
||||
private int line;
|
||||
@@ -590,9 +592,7 @@ class Parser implements Function<String, Expression> {
|
||||
}
|
||||
if (literal == Result.NOT_FOUND) {
|
||||
if (namespace != null) {
|
||||
// TODO use constants!
|
||||
typeCheckInfo = "[" + Expressions.TYPECHECK_NAMESPACE_PLACEHOLDER + "]";
|
||||
typeCheckInfo += "." + parts.stream().collect(Collectors.joining("."));
|
||||
typeCheckInfo = TYPE_CHECK_NAMESPACE + parts.stream().collect(Collectors.joining("."));
|
||||
} else if (typeInfos.containsKey(parts.get(0))) {
|
||||
typeCheckInfo = typeInfos.get(parts.get(0));
|
||||
if (typeCheckInfo != null) {
|
||||
|
||||
@@ -10,20 +10,23 @@ import java.util.concurrent.CompletionStage;
|
||||
public interface ResolutionContext {
|
||||
|
||||
/**
|
||||
* Parse and evaluate the expression.
|
||||
*
|
||||
* @param expression
|
||||
* @return the result of the evaluated expression
|
||||
* @return the result
|
||||
*/
|
||||
CompletionStage<Object> evaluate(String expression);
|
||||
|
||||
/**
|
||||
* Evaluate the expression.
|
||||
*
|
||||
* @param expression
|
||||
* @return the result of the evaluated expression
|
||||
* @return the result
|
||||
*/
|
||||
CompletionStage<Object> evaluate(Expression expression);
|
||||
|
||||
/**
|
||||
* Create a child resolution context with the specified data and namespace resolvers.
|
||||
*
|
||||
* @param data
|
||||
* @param namespaceResolversFactories
|
||||
@@ -32,6 +35,7 @@ public interface ResolutionContext {
|
||||
ResolutionContext createChild(Object data, List<NamespaceResolver> namespaceResolvers);
|
||||
|
||||
/**
|
||||
* Create a child resolution context with the specifiec extending blocks.
|
||||
*
|
||||
* @param extendingBlocks
|
||||
* @return a new child resolution context
|
||||
@@ -59,7 +63,7 @@ public interface ResolutionContext {
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @return the extending block or null
|
||||
* @return the extending block for the specified name or null
|
||||
*/
|
||||
SectionBlock getExtendingBlock(String name);
|
||||
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
import io.quarkus.qute.Results.Result;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
*
|
||||
* @see ValueResolver
|
||||
* @see NamespaceResolver
|
||||
*/
|
||||
public interface Resolver {
|
||||
|
||||
/**
|
||||
* This method should return {@link Result#NOT_FOUND} if it's not possible to resolve the context. Any other value is
|
||||
* considered a valid result, including {@code null}.
|
||||
*
|
||||
* @param context
|
||||
* @return the result
|
||||
* @see Results#NOT_FOUND
|
||||
*/
|
||||
CompletionStage<Object> resolve(EvalContext context);
|
||||
|
||||
|
||||
@@ -3,10 +3,16 @@ package io.quarkus.qute;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class Results {
|
||||
/**
|
||||
* Result constants.
|
||||
*/
|
||||
public final class Results {
|
||||
|
||||
public static final CompletionStage<Object> NOT_FOUND = CompletableFuture.completedFuture(Result.NOT_FOUND);
|
||||
|
||||
private Results() {
|
||||
}
|
||||
|
||||
public enum Result {
|
||||
|
||||
NOT_FOUND,
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
* Defines the logic of a section node.
|
||||
*
|
||||
* @see SectionHelperFactory
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SectionHelper {
|
||||
|
||||
@@ -9,6 +9,8 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Factory to create a new {@link SectionHelper} based on the {@link SectionInitContextImpl}.
|
||||
*
|
||||
* @see EngineBuilder#addSectionHelper(SectionHelperFactory)
|
||||
*/
|
||||
public interface SectionHelperFactory<T extends SectionHelper> {
|
||||
|
||||
@@ -16,7 +18,7 @@ public interface SectionHelperFactory<T extends SectionHelper> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the list of default aliases
|
||||
* @return the list of default aliases used to match the helper
|
||||
*/
|
||||
default List<String> getDefaultAliases() {
|
||||
return Collections.emptyList();
|
||||
@@ -32,8 +34,6 @@ public interface SectionHelperFactory<T extends SectionHelper> {
|
||||
|
||||
/**
|
||||
* A nested section tag that matches a name of a block will be added as a block to the current section.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @return the list of block labels
|
||||
*/
|
||||
@@ -41,6 +41,13 @@ public interface SectionHelperFactory<T extends SectionHelper> {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, all unknown nested sections are ignored, ie. sections with labels not present in the
|
||||
* {@link #getBlockLabels()}. However, sometimes it might be useful to treat such sections as blocks. See
|
||||
* {@link IncludeSectionHelper} for an example.
|
||||
*
|
||||
* @return true if unknown sections should not be ignored
|
||||
*/
|
||||
default boolean treatUnknownSectionsAsBlocks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A result node backed by an object value.
|
||||
* A result node backed by a single object value.
|
||||
*/
|
||||
public class SingleResultNode implements ResultNode {
|
||||
|
||||
|
||||
@@ -4,11 +4,21 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a template definition.
|
||||
* Represents an immutable template definition.
|
||||
* <p>
|
||||
* The workflow is as follows:
|
||||
* <ol>
|
||||
* <li>Create a new template instance via {@link #instance()} or any convenient method</li>
|
||||
* <li>Set the model data</li>
|
||||
* <li>Trigger rendering with {@link TemplateInstance#render()}, {@link TemplateInstance#renderAsync()},
|
||||
* {@link TemplateInstance#consume(java.util.function.Consumer)} or subscribe to a publisher returned from
|
||||
* {@link TemplateInstance#publisher()}</li>
|
||||
* </ol>
|
||||
*/
|
||||
public interface Template {
|
||||
|
||||
/**
|
||||
* Template instance represents a rendering configuration.
|
||||
*
|
||||
* @return a new template instance
|
||||
*/
|
||||
|
||||
@@ -9,10 +9,8 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A value resolver is automatically generated for a target type.
|
||||
* <p>
|
||||
* Note that non-public members, constructors, static initializers, static, synthetic and void methods are always ignored.
|
||||
* </p>
|
||||
* This annotation is used to mark a target type for which a value resolver should be automatically generated. Note that
|
||||
* non-public members, constructors, static initializers, static, synthetic and void methods are always ignored.
|
||||
*
|
||||
* @see ValueResolver
|
||||
*/
|
||||
@@ -27,7 +25,7 @@ public @interface TemplateData {
|
||||
Class<?> target() default TemplateData.class;
|
||||
|
||||
/**
|
||||
* The regular expressions that are used to match the members that should be ignored
|
||||
* The regular expressions that are used to match the members that should be ignored.
|
||||
*/
|
||||
String[] ignore() default {};
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import java.io.Reader;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Locates template sources.
|
||||
* Locates template sources. The locator with higher priority takes precedence.
|
||||
*
|
||||
* @see Engine#getTemplate(String)
|
||||
*/
|
||||
public interface TemplateLocator extends WithPriority {
|
||||
|
||||
/**
|
||||
* Must return {@link Optional#empty()} if it's not possible to locate a template with the specified id.
|
||||
*
|
||||
* @param id
|
||||
* @return the template location for the given id
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
import io.quarkus.qute.Results.Result;
|
||||
|
||||
/**
|
||||
* Value resolver.
|
||||
* Value resolvers are used when evaluating expressions.
|
||||
* <p>
|
||||
* First the resolvers that apply to the given {@link EvalContext} are filtered. Then the resolver with highest priority is used
|
||||
* to resolve the data. If {@link Result#NOT_FOUND} is returned the next available resolver is tried.
|
||||
*
|
||||
* @see EvalContext
|
||||
*/
|
||||
public interface ValueResolver extends Resolver, WithPriority {
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EngineBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testDuplicateNamespace() {
|
||||
try {
|
||||
Engine.builder().addNamespaceResolver(NamespaceResolver.builder("foo").resolve(e -> {
|
||||
return null;
|
||||
}).build()).addNamespaceResolver(NamespaceResolver.builder("foo").resolve(e -> {
|
||||
return null;
|
||||
}).build());
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LiteralSupportTest {
|
||||
|
||||
@Test
|
||||
public void testNumbers() {
|
||||
assertEquals(Integer.valueOf(43), LiteralSupport.getLiteral("43"));
|
||||
assertEquals(Long.valueOf(1000), LiteralSupport.getLiteral("1000l"));
|
||||
assertEquals(Long.valueOf(-10), LiteralSupport.getLiteral("-10L"));
|
||||
assertEquals(Double.valueOf(1.0d), LiteralSupport.getLiteral("1d"));
|
||||
assertEquals(Double.valueOf(2.12d), LiteralSupport.getLiteral("+2.12d"));
|
||||
assertEquals(Double.valueOf(-2.12d), LiteralSupport.getLiteral("-2.12d"));
|
||||
assertEquals(Double.valueOf(123.4d), LiteralSupport.getLiteral("123.4D"));
|
||||
assertEquals(Float.valueOf(2.12f), LiteralSupport.getLiteral("2.12f"));
|
||||
assertEquals(Float.valueOf(2.12f), LiteralSupport.getLiteral("2.12F"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleans() {
|
||||
assertEquals(Boolean.TRUE, LiteralSupport.getLiteral("true"));
|
||||
assertEquals(Boolean.FALSE, LiteralSupport.getLiteral("false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNull() {
|
||||
assertNull(LiteralSupport.getLiteral("null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
assertEquals("foo", LiteralSupport.getLiteral("'foo'"));
|
||||
assertEquals("foo", LiteralSupport.getLiteral("\"foo\""));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user