http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java ---------------------------------------------------------------------- diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java deleted file mode 100644 index c01422e..0000000 --- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 org.apache.freemarker.core.model.impl; - -public interface Java8DefaultMethodsBeanBase { - - static final String DEFAULT_METHOD_PROP = "defaultMethodProp"; - static final String DEFAULT_METHOD_PROP_VALUE = "defaultMethodPropValue"; - static final String DEFAULT_METHOD_PROP_2 = "defaultMethodProp2"; - static final String DEFAULT_METHOD_INDEXED_PROP = "defaultMethodIndexedProp"; - static final String DEFAULT_METHOD_INDEXED_PROP_GETTER = "getDefaultMethodIndexedProp"; - static final String DEFAULT_METHOD_INDEXED_PROP_VALUE = "defaultMethodIndexedPropValue"; - static final String DEFAULT_METHOD_INDEXED_PROP_2 = "defaultMethodIndexedProp2"; - static final String DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0 = "defaultMethodIndexedProp2(0).value"; - static final String DEFAULT_METHOD_INDEXED_PROP_3 = "defaultMethodIndexedProp3"; - static final String DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0 = "indexedProp3Value[0]"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP = "defaultMethodNotAnIndexedProp"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_VALUE = "defaultMethodNotAnIndexedPropValue"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2 = "defaultMethodNotAnIndexedProp2"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE = "defaultMethodNotAnIndexedProp2Value"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3 = "defaultMethodNotAnIndexedProp3"; - static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 = "defaultMethodNotAnIndexedProp3Value[0]"; - static final String DEFAULT_METHOD_ACTION = "defaultMethodAction"; - static final String DEFAULT_METHOD_ACTION_RETURN_VALUE = "defaultMethodActionReturnValue"; - static final String OVERRIDDEN_DEFAULT_METHOD_ACTION = "overriddenDefaultMethodAction"; - - default String getDefaultMethodProp() { - return DEFAULT_METHOD_PROP_VALUE; - } - - default String getDefaultMethodProp2() { - return ""; - } - - /** - * Will be kept as there's no non-indexed read methods for this. - */ - default String getDefaultMethodIndexedProp(int i) { - return DEFAULT_METHOD_INDEXED_PROP_VALUE; - } - - /** - * Will be kept as there will be a matching non-indexed read method in the subclass. - * However, as of FM3, the non-indexed read method is used if it's available. - */ - default String getDefaultMethodIndexedProp2(int i) { - return DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0; - } - - /** - * This is not an indexed reader method, but a matching indexed reader method will be added in the subclass. - * However, as of FM3, the non-indexed read method is used if it's available. - */ - default String[] getDefaultMethodIndexedProp3() { - return new String[] {DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0}; - } - - /** Will be discarded because of a non-matching non-indexed read method in a subclass */ - default String getDefaultMethodNotAnIndexedProp(int i) { - return ""; - } - - /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */ - default String getDefaultMethodNotAnIndexedProp2() { - return DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE; - } - - /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */ - default String[] getDefaultMethodNotAnIndexedProp3() { - return new String[] { DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 }; - } - - default String defaultMethodAction() { - return DEFAULT_METHOD_ACTION_RETURN_VALUE; - } - - default Object overriddenDefaultMethodAction() { - return null; - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java deleted file mode 100644 index 495f3f9..0000000 --- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 org.apache.freemarker.core.model.impl; - -import static org.junit.Assert.*; - -import java.util.Collections; - -import org.junit.Test; - -import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.model.TemplateHashModel; -import org.apache.freemarker.core.model.TemplateMethodModelEx; -import org.apache.freemarker.core.model.TemplateModelException; - -public class Java8DefaultObjectWrapperBridgeMethodsTest { - - @Test - public void testWithoutDefaultMethod() throws TemplateModelException { - test(BridgeMethodsBean.class); - } - - @Test - public void testWithDefaultMethod() throws TemplateModelException { - test(Java8BridgeMethodsWithDefaultMethodBean.class); - } - - @Test - public void testWithDefaultMethod2() throws TemplateModelException { - test(Java8BridgeMethodsWithDefaultMethodBean2.class); - } - - private void test(Class<?> pClass) throws TemplateModelException { - DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build(); - TemplateHashModel wrapped; - try { - wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance()); - } catch (Exception e) { - throw new IllegalStateException(e); - } - - TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1"); - assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList())); - - TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2"); - assertNull(m2.exec(Collections.emptyList())); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java deleted file mode 100644 index 905d536..0000000 --- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 org.apache.freemarker.core.model.impl; - -import static org.junit.Assert.*; - -import java.util.Collections; - -import org.junit.Test; - -import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.model.TemplateHashModel; -import org.apache.freemarker.core.model.TemplateMethodModelEx; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.TemplateNumberModel; -import org.apache.freemarker.core.model.TemplateScalarModel; -import org.apache.freemarker.core.model.TemplateSequenceModel; - -public class Java8DefaultObjectWrapperTest { - - @Test - public void testDefaultMethodRecognized() throws TemplateModelException { - DefaultObjectWrapper.Builder owb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0); - DefaultObjectWrapper ow = owb.build(); - TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean()); - - { - TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString()); - } - { - // This is overridden in the subclass, so it's visible even without default method support: - TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString()); - } - { - TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( - Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString()); - } - { - // Has only indexed read method, so it's not exposed as a property - assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP)); - - TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_GETTER); - assertNotNull(indexedReadMethod); - assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE, - ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0)))) - .getAsString - ()); - } - { - // We see default method indexed read method, but it's invalidated by normal getter in the subclass - TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber()); - } - { - // The default method read method invalidates the indexed read method in the subclass - TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString()); - } - { - // The default method read method invalidates the indexed read method in the subclass - TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0, - ((TemplateScalarModel) prop.get(0)).getAsString()); - } - { - // We see the default method indexed reader, which overrides the plain array reader in the subclass. - TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0, - ((TemplateScalarModel) prop.get(0)).getAsString()); - } - { - // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that - // takes over. - TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3); - assertNotNull(prop); - assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0, - ((TemplateScalarModel) prop.get(0)).getAsString()); - } - { - // Only present in the subclass. - - // Has only indexed read method, so it's not exposed as a property - assertNull(wrappedBean.get(Java8DefaultMethodsBean.INDEXED_PROP_4)); - - TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBean.INDEXED_PROP_GETTER_4); - assertNotNull(indexedReadMethod); - assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE, - ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0)))) - .getAsString()); - } - { - TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBean.NORMAL_ACTION); - assertNotNull(action); - assertEquals( - Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE, - ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); - } - - { - TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBean.NORMAL_ACTION); - assertNotNull(action); - assertEquals( - Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE, - ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); - } - { - TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION); - assertNotNull(action); - assertEquals( - Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE, - ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); - } - { - TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( - Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION); - assertNotNull(action); - assertEquals( - Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE, - ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/build.gradle ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/build.gradle b/freemarker-core-test-java8/build.gradle new file mode 100644 index 0000000..44b95ae --- /dev/null +++ b/freemarker-core-test-java8/build.gradle @@ -0,0 +1,25 @@ +description = """\ +The unit tests of freemarker-core that need Java 8 features. These were moved to a separate project to avoid \ +a project that contains java files that require varous Java versions. +""" + +// Override inherited default Java version: +sourceCompatibility = "1.8" +targetCompatibility = "1.8" +[compileJava, compileTestJava]*.options*.bootClasspath = bootClasspathJava8 + +dependencies { + compile project(":freemarker-core") + compile project(":freemarker-test-utils") +} + +// We have nothing to put into the jar, as we have test classes only +jar.enabled = false + +javadoc.enabled = false + +// Must not be deployed to a public Maven repository +uploadArchives.enabled = false + +// Doesn't make sense to Maven "install" this, as the artifact won't contain test classes +install.enabled = false http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER b/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER new file mode 100644 index 0000000..569ba05 --- /dev/null +++ b/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER @@ -0,0 +1,8 @@ +Apache FreeMarker is an effort undergoing incubation at The Apache Software +Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of +all newly accepted projects until a further review indicates that the +infrastructure, communications, and decision making process have stabilized in +a manner consistent with other successful ASF projects. While incubation +status is not necessarily a reflection of the completeness or stability of the +code, it does indicate that the project has yet to be fully endorsed by the +ASF. \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE b/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java new file mode 100644 index 0000000..2c9d4e9 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public class BridgeMethodsBean extends BridgeMethodsBeanBase<String> { + + static final String M1_RETURN_VALUE = "m1ReturnValue"; + + @Override + public String m1() { + return M1_RETURN_VALUE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java new file mode 100644 index 0000000..4ecec7c --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public abstract class BridgeMethodsBeanBase<T> { + + public abstract T m1(); + + public T m2() { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java new file mode 100644 index 0000000..c7d27a6 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public class Java8BridgeMethodsWithDefaultMethodBean implements Java8BridgeMethodsWithDefaultMethodBeanBase<String> { + + static final String M1_RETURN_VALUE = "m1ReturnValue"; + + public String m1() { + return M1_RETURN_VALUE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java new file mode 100644 index 0000000..7dfb39a --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public class Java8BridgeMethodsWithDefaultMethodBean2 implements Java8BridgeMethodsWithDefaultMethodBeanBase2 { + // All inherited +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java new file mode 100644 index 0000000..fdd8821 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public interface Java8BridgeMethodsWithDefaultMethodBeanBase<T> { + + default T m1() { + return null; + } + + default T m2() { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java new file mode 100644 index 0000000..6f68dc7 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public interface Java8BridgeMethodsWithDefaultMethodBeanBase2 extends Java8BridgeMethodsWithDefaultMethodBeanBase<String> { + + @Override + default String m1() { + return Java8BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java new file mode 100644 index 0000000..eabc3d0 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public class Java8DefaultMethodsBean implements Java8DefaultMethodsBeanBase { + + static final String NORMAL_PROP = "normalProp"; + static final String NORMAL_PROP_VALUE = "normalPropValue"; + static final String PROP_2_OVERRIDE_VALUE = "prop2OverrideValue"; + static final int NOT_AN_INDEXED_PROP_VALUE = 1; + static final String ARRAY_PROP_2_VALUE_0 = "arrayProp2[0].value"; + private static final int NOT_AN_INDEXED_PROP_3_VALUE = 3; + private static final String NOT_AN_INDEXED_PROP_2_VALUE = "notAnIndecedProp2Value"; + static final String INDEXED_PROP_4 = "indexedProp4"; + static final String INDEXED_PROP_GETTER_4 = "getIndexedProp4"; + static final String INDEXED_PROP_4_VALUE = "indexedProp4Value[0]"; + static final String NORMAL_ACTION = "normalAction"; + static final String NORMAL_ACTION_RETURN_VALUE = "normalActionReturnValue"; + static final String OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE = "overriddenValue"; + + public String getNormalProp() { + return NORMAL_PROP_VALUE; + } + + @Override + public String getDefaultMethodProp2() { + return PROP_2_OVERRIDE_VALUE; + } + + public String[] getDefaultMethodIndexedProp2() { + return new String[] { ARRAY_PROP_2_VALUE_0 }; + } + + /** + * There's a matching non-indexed reader method in the base class, but as this is indexed, it takes over. + */ + public String getDefaultMethodIndexedProp3(int index) { + return ""; + } + + public int getDefaultMethodNotAnIndexedProp() { + return NOT_AN_INDEXED_PROP_VALUE; + } + + /** Actually, this will be indexed if the default method support is off. */ + public String getDefaultMethodNotAnIndexedProp2(int index) { + return NOT_AN_INDEXED_PROP_2_VALUE; + } + + /** Actually, this will be indexed if the default method support is off. */ + public int getDefaultMethodNotAnIndexedProp3(int index) { + return NOT_AN_INDEXED_PROP_3_VALUE; + } + + public String getIndexedProp4(int index) { + return INDEXED_PROP_4_VALUE; + } + + public String normalAction() { + return NORMAL_ACTION_RETURN_VALUE; + } + + @Override + public String overriddenDefaultMethodAction() { + return OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java new file mode 100644 index 0000000..c01422e --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +public interface Java8DefaultMethodsBeanBase { + + static final String DEFAULT_METHOD_PROP = "defaultMethodProp"; + static final String DEFAULT_METHOD_PROP_VALUE = "defaultMethodPropValue"; + static final String DEFAULT_METHOD_PROP_2 = "defaultMethodProp2"; + static final String DEFAULT_METHOD_INDEXED_PROP = "defaultMethodIndexedProp"; + static final String DEFAULT_METHOD_INDEXED_PROP_GETTER = "getDefaultMethodIndexedProp"; + static final String DEFAULT_METHOD_INDEXED_PROP_VALUE = "defaultMethodIndexedPropValue"; + static final String DEFAULT_METHOD_INDEXED_PROP_2 = "defaultMethodIndexedProp2"; + static final String DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0 = "defaultMethodIndexedProp2(0).value"; + static final String DEFAULT_METHOD_INDEXED_PROP_3 = "defaultMethodIndexedProp3"; + static final String DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0 = "indexedProp3Value[0]"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP = "defaultMethodNotAnIndexedProp"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_VALUE = "defaultMethodNotAnIndexedPropValue"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2 = "defaultMethodNotAnIndexedProp2"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE = "defaultMethodNotAnIndexedProp2Value"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3 = "defaultMethodNotAnIndexedProp3"; + static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 = "defaultMethodNotAnIndexedProp3Value[0]"; + static final String DEFAULT_METHOD_ACTION = "defaultMethodAction"; + static final String DEFAULT_METHOD_ACTION_RETURN_VALUE = "defaultMethodActionReturnValue"; + static final String OVERRIDDEN_DEFAULT_METHOD_ACTION = "overriddenDefaultMethodAction"; + + default String getDefaultMethodProp() { + return DEFAULT_METHOD_PROP_VALUE; + } + + default String getDefaultMethodProp2() { + return ""; + } + + /** + * Will be kept as there's no non-indexed read methods for this. + */ + default String getDefaultMethodIndexedProp(int i) { + return DEFAULT_METHOD_INDEXED_PROP_VALUE; + } + + /** + * Will be kept as there will be a matching non-indexed read method in the subclass. + * However, as of FM3, the non-indexed read method is used if it's available. + */ + default String getDefaultMethodIndexedProp2(int i) { + return DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0; + } + + /** + * This is not an indexed reader method, but a matching indexed reader method will be added in the subclass. + * However, as of FM3, the non-indexed read method is used if it's available. + */ + default String[] getDefaultMethodIndexedProp3() { + return new String[] {DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0}; + } + + /** Will be discarded because of a non-matching non-indexed read method in a subclass */ + default String getDefaultMethodNotAnIndexedProp(int i) { + return ""; + } + + /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */ + default String getDefaultMethodNotAnIndexedProp2() { + return DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE; + } + + /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */ + default String[] getDefaultMethodNotAnIndexedProp3() { + return new String[] { DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 }; + } + + default String defaultMethodAction() { + return DEFAULT_METHOD_ACTION_RETURN_VALUE; + } + + default Object overriddenDefaultMethodAction() { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java new file mode 100644 index 0000000..495f3f9 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; + +import org.apache.freemarker.core.Configuration; +import org.apache.freemarker.core.model.TemplateHashModel; +import org.apache.freemarker.core.model.TemplateMethodModelEx; +import org.apache.freemarker.core.model.TemplateModelException; + +public class Java8DefaultObjectWrapperBridgeMethodsTest { + + @Test + public void testWithoutDefaultMethod() throws TemplateModelException { + test(BridgeMethodsBean.class); + } + + @Test + public void testWithDefaultMethod() throws TemplateModelException { + test(Java8BridgeMethodsWithDefaultMethodBean.class); + } + + @Test + public void testWithDefaultMethod2() throws TemplateModelException { + test(Java8BridgeMethodsWithDefaultMethodBean2.class); + } + + private void test(Class<?> pClass) throws TemplateModelException { + DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build(); + TemplateHashModel wrapped; + try { + wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance()); + } catch (Exception e) { + throw new IllegalStateException(e); + } + + TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1"); + assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList())); + + TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2"); + assertNull(m2.exec(Collections.emptyList())); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java new file mode 100644 index 0000000..905d536 --- /dev/null +++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core.model.impl; + +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; + +import org.apache.freemarker.core.Configuration; +import org.apache.freemarker.core.model.TemplateHashModel; +import org.apache.freemarker.core.model.TemplateMethodModelEx; +import org.apache.freemarker.core.model.TemplateModelException; +import org.apache.freemarker.core.model.TemplateNumberModel; +import org.apache.freemarker.core.model.TemplateScalarModel; +import org.apache.freemarker.core.model.TemplateSequenceModel; + +public class Java8DefaultObjectWrapperTest { + + @Test + public void testDefaultMethodRecognized() throws TemplateModelException { + DefaultObjectWrapper.Builder owb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0); + DefaultObjectWrapper ow = owb.build(); + TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean()); + + { + TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString()); + } + { + // This is overridden in the subclass, so it's visible even without default method support: + TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString()); + } + { + TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( + Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString()); + } + { + // Has only indexed read method, so it's not exposed as a property + assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP)); + + TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_GETTER); + assertNotNull(indexedReadMethod); + assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE, + ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0)))) + .getAsString + ()); + } + { + // We see default method indexed read method, but it's invalidated by normal getter in the subclass + TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber()); + } + { + // The default method read method invalidates the indexed read method in the subclass + TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString()); + } + { + // The default method read method invalidates the indexed read method in the subclass + TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0, + ((TemplateScalarModel) prop.get(0)).getAsString()); + } + { + // We see the default method indexed reader, which overrides the plain array reader in the subclass. + TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0, + ((TemplateScalarModel) prop.get(0)).getAsString()); + } + { + // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that + // takes over. + TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3); + assertNotNull(prop); + assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0, + ((TemplateScalarModel) prop.get(0)).getAsString()); + } + { + // Only present in the subclass. + + // Has only indexed read method, so it's not exposed as a property + assertNull(wrappedBean.get(Java8DefaultMethodsBean.INDEXED_PROP_4)); + + TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBean.INDEXED_PROP_GETTER_4); + assertNotNull(indexedReadMethod); + assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE, + ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0)))) + .getAsString()); + } + { + TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBean.NORMAL_ACTION); + assertNotNull(action); + assertEquals( + Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE, + ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); + } + + { + TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBean.NORMAL_ACTION); + assertNotNull(action); + assertEquals( + Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE, + ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); + } + { + TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION); + assertNotNull(action); + assertEquals( + Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE, + ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); + } + { + TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get( + Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION); + assertNotNull(action); + assertEquals( + Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE, + ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString()); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/build.gradle ---------------------------------------------------------------------- diff --git a/freemarker-core-test/build.gradle b/freemarker-core-test/build.gradle new file mode 100644 index 0000000..411f6ea --- /dev/null +++ b/freemarker-core-test/build.gradle @@ -0,0 +1,19 @@ +description = """\ +The unit tests of freemarker-core. These tests used to be in freemarker-core, but to avoid depenency loop \ +through freemarker-test-utils, they had to be moved into a separate project.""" + +dependencies { + compile project(":freemarker-core") + compile project(":freemarker-test-utils") +} + +// We have nothing to put into the jar, as we have test classes only +jar.enabled = false + +javadoc.enabled = false + +// Must not be deployed to a public Maven repository +uploadArchives.enabled = false + +// Doesn't make sense to Maven "install" this, as the artifact won't contain test classes +install.enabled = false http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java new file mode 100644 index 0000000..10d63b3 --- /dev/null +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core; + +import java.util.Map; + +import org.apache.freemarker.test.TemplateTest; +import org.junit.Test; + +public class ASTBasedErrorMessagesTest extends TemplateTest { + + @Test + public void testInvalidRefBasic() { + assertErrorContains("${foo}", "foo", "specify a default"); + assertErrorContains("${map[foo]}", "foo", "\\!map[", "specify a default"); + } + + @Test + public void testInvalidRefDollar() { + assertErrorContains("${$x}", "$x", "must not start with \"$\"", "specify a default"); + assertErrorContains("${map.$x}", "map.$x", "must not start with \"$\"", "specify a default"); + } + + @Test + public void testInvalidRefAfterDot() { + assertErrorContains("${map.foo.bar}", "map.foo", "\\!foo.bar", "after the last dot", "specify a default"); + } + + @Test + public void testInvalidRefInSquareBrackets() { + assertErrorContains("${map['foo']}", "map", "final [] step", "specify a default"); + } + + @Test + public void testInvalidRefSize() { + assertErrorContains("${map.size()}", "map.size", "?size", "specify a default"); + assertErrorContains("${map.length()}", "map.length", "?length", "specify a default"); + } + + @Override + protected Object createDataModel() { + Map<String, Object> dataModel = createCommonTestValuesDataModel(); + dataModel.put("overloads", new Overloads()); + return dataModel; + } + + public static class Overloads { + + @SuppressWarnings("unused") + public void m(String s) {} + + @SuppressWarnings("unused") + public void m(int i) {} + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java new file mode 100644 index 0000000..3518b29 --- /dev/null +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java @@ -0,0 +1,438 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.FTLUtil; +import org.apache.freemarker.core.util._ClassUtil; +import org.apache.freemarker.core.util._StringUtil; +import org.apache.freemarker.test.TestConfigurationBuilder; + +/** + * Static methods and command-line tool for printing the AST of a template. + */ +public class ASTPrinter { + + private final Configuration cfg; + private int successfulCounter; + private int failedCounter; + + static public void main(String[] args) throws IOException { + if (args.length == 0) { + usage(); + System.exit(-1); + } + + ASTPrinter astp = new ASTPrinter(); + if (args[0].equalsIgnoreCase("-r")) { + astp.mainRecursive(args); + } else { + astp.mainSingleTemplate(args); + } + } + + private ASTPrinter() { + cfg = new TestConfigurationBuilder(Configuration.VERSION_3_0_0).build(); + } + + private void mainSingleTemplate(String[] args) throws IOException, FileNotFoundException { + final String templateFileName; + final String templateContent; + if (args[0].startsWith("ftl:")) { + templateFileName = null; + templateContent = args[0]; + } else { + templateFileName = args[0]; + templateContent = null; + } + + Template t = new Template( + templateFileName, + templateFileName == null ? new StringReader(templateContent) : new FileReader(templateFileName), + cfg); + + p(getASTAsString(t)); + } + + private void mainRecursive(String[] args) throws IOException { + if (args.length != 4) { + p("Number of arguments must be 4, but was: " + args.length); + usage(); + System.exit(-1); + } + + final String srcDirPath = args[1].trim(); + File srcDir = new File(srcDirPath); + if (!srcDir.isDirectory()) { + p("This should be an existing directory: " + srcDirPath); + System.exit(-1); + } + + Pattern fnPattern; + try { + fnPattern = Pattern.compile(args[2]); + } catch (PatternSyntaxException e) { + p(_StringUtil.jQuote(args[2]) + " is not a valid regular expression"); + System.exit(-1); + return; + } + + final String dstDirPath = args[3].trim(); + File dstDir = new File(dstDirPath); + if (!dstDir.isDirectory()) { + p("This should be an existing directory: " + dstDirPath); + System.exit(-1); + } + + long startTime = System.currentTimeMillis(); + recurse(srcDir, fnPattern, dstDir); + long endTime = System.currentTimeMillis(); + + p("Templates successfully processed " + successfulCounter + ", failed " + failedCounter + + ". Time taken: " + (endTime - startTime) / 1000.0 + " s"); + } + + private void recurse(File srcDir, Pattern fnPattern, File dstDir) throws IOException { + File[] files = srcDir.listFiles(); + if (files == null) { + throw new IOException("Failed to kust directory: " + srcDir); + } + for (File file : files) { + if (file.isDirectory()) { + recurse(file, fnPattern, new File(dstDir, file.getName())); + } else { + if (fnPattern.matcher(file.getName()).matches()) { + File dstFile = new File(dstDir, file.getName()); + String res; + try { + Template t = new Template(file.getPath().replace('\\', '/'), loadIntoString(file), cfg); + res = getASTAsString(t); + successfulCounter++; + } catch (ParseException e) { + res = "<<<FAILED>>>\n" + e.getMessage(); + failedCounter++; + p(""); + p("-------------------------failed-------------------------"); + p("Error message was saved into: " + dstFile.getAbsolutePath()); + p(""); + p(e.getMessage()); + } + save(res, dstFile); + } + } + } + } + + private String loadIntoString(File file) throws IOException { + long ln = file.length(); + if (ln < 0) { + throw new IOException("Failed to get the length of " + file); + } + byte[] buffer = new byte[(int) ln]; + InputStream in = new FileInputStream(file); + try { + int offset = 0; + int bytesRead; + while (offset < buffer.length) { + bytesRead = in.read(buffer, offset, buffer.length - offset); + if (bytesRead == -1) { + throw new IOException("Unexpected end of file: " + file); + } + offset += bytesRead; + } + } finally { + in.close(); + } + + try { + return decode(buffer, StandardCharsets.UTF_8); + } catch (CharacterCodingException e) { + return decode(buffer, StandardCharsets.ISO_8859_1); + } + } + + private String decode(byte[] buffer, Charset charset) throws CharacterCodingException { + return charset.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT) + .decode(ByteBuffer.wrap(buffer)).toString(); + } + + private void save(String astStr, File file) throws IOException { + File parentDir = file.getParentFile(); + if (!parentDir.isDirectory() && !parentDir.mkdirs()) { + throw new IOException("Failed to invoke parent directory: " + parentDir); + } + + Writer w = new BufferedWriter(new FileWriter(file)); + try { + w.write(astStr); + } finally { + w.close(); + } + } + + private static void usage() { + p("Prints template Abstract Syntax Tree (AST) as plain text."); + p("Usage:"); + p(" java org.apache.freemarker.core.PrintAST <templateFile>"); + p(" java org.apache.freemarker.core.PrintAST ftl:<templateSource>"); + p(" java org.apache.freemarker.core.PrintAST -r <src-directory> <regexp> <dst-directory>"); + } + + private static final String INDENTATION = " "; + + public static String getASTAsString(String ftl) throws IOException { + return getASTAsString(ftl, (Options) null); + } + + public static String getASTAsString(String ftl, Options opts) throws IOException { + return getASTAsString(null, ftl, opts); + } + + public static String getASTAsString(String templateName, String ftl) throws IOException { + return getASTAsString(templateName, ftl, null); + } + + public static String getASTAsString(String templateName, String ftl, Options opts) throws IOException { + Template t = new Template(templateName, ftl, new TestConfigurationBuilder().build()); + return getASTAsString(t, opts); + } + + public static String getASTAsString(Template t) throws IOException { + return getASTAsString(t, null); + } + + public static String getASTAsString(Template t, Options opts) throws IOException { + validateAST(t); + + StringWriter out = new StringWriter(); + printNode(t.getRootASTNode(), "", null, opts != null ? opts : Options.DEFAULT_INSTANCE, out); + return out.toString(); + } + + public static void validateAST(Template t) throws InvalidASTException { + final ASTElement node = t.getRootASTNode(); + if (node.getParent() != null) { + throw new InvalidASTException("Root node parent must be null." + + "\nRoot node: " + node.dump(false) + + "\nParent" + + ": " + node.getParent().getClass() + ", " + node.getParent().dump(false)); + } + validateAST(node); + } + + private static void validateAST(ASTElement te) { + int childCount = te.getChildCount(); + for (int i = 0; i < childCount; i++) { + ASTElement child = te.getChild(i); + ASTElement parentElement = child.getParent(); + // As ASTImplicitParent.accept does nothing but returns its children, it's optimized out in the final + // AST tree. While it will be present as a child, the parent element also will have children + // that contains the children of the ASTImplicitParent directly. + if (parentElement instanceof ASTImplicitParent && parentElement.getParent() != null) { + parentElement = parentElement.getParent(); + } + if (parentElement != te) { + throw new InvalidASTException("Wrong parent node." + + "\nNode: " + child.dump(false) + + "\nExpected parent: " + te.dump(false) + + "\nActual parent: " + parentElement.dump(false)); + } + if (child.getIndex() != i) { + throw new InvalidASTException("Wrong node index." + + "\nNode: " + child.dump(false) + + "\nExpected index: " + i + + "\nActual index: " + child.getIndex()); + } + } + if (te instanceof ASTImplicitParent && te.getChildCount() < 2) { + throw new InvalidASTException("Mixed content with child count less than 2 should removed by optimizatoin, " + + "but found one with " + te.getChildCount() + " child(ren)."); + } + ASTElement[] children = te.getChildBuffer(); + if (children != null) { + if (childCount == 0) { + throw new InvalidASTException( + "Children must be null when childCount is 0." + + "\nNode: " + te.dump(false)); + } + for (int i = 0; i < te.getChildCount(); i++) { + if (children[i] == null) { + throw new InvalidASTException( + "Child can't be null at index " + i + + "\nNode: " + te.dump(false)); + } + } + for (int i = te.getChildCount(); i < children.length; i++) { + if (children[i] != null) { + throw new InvalidASTException( + "Children can't be non-null at index " + i + + "\nNode: " + te.dump(false)); + } + } + } else { + if (childCount != 0) { + throw new InvalidASTException( + "Children mustn't be null when child count isn't 0." + + "\nNode: " + te.dump(false)); + } + } + } + + private static void printNode(Object node, String ind, ParameterRole paramRole, Options opts, Writer out) throws IOException { + if (node instanceof ASTNode) { + ASTNode tObj = (ASTNode) node; + + printNodeLineStart(paramRole, ind, out); + out.write(tObj.getNodeTypeSymbol()); + printNodeLineEnd(node, out, opts); + + if (opts.getShowConstantValue() && node instanceof ASTExpression) { + TemplateModel tm = ((ASTExpression) node).constantValue; + if (tm != null) { + out.write(INDENTATION); + out.write(ind); + out.write("= const "); + out.write(FTLUtil.getTypeDescription(tm)); + out.write(' '); + out.write(tm.toString()); + out.write('\n'); + } + } + + int paramCnt = tObj.getParameterCount(); + for (int i = 0; i < paramCnt; i++) { + ParameterRole role = tObj.getParameterRole(i); + if (role == null) throw new NullPointerException("parameter role"); + Object value = tObj.getParameterValue(i); + printNode(value, ind + INDENTATION, role, opts, out); + } + if (tObj instanceof ASTElement) { + Enumeration enu = ((ASTElement) tObj).children(); + while (enu.hasMoreElements()) { + printNode(enu.nextElement(), INDENTATION + ind, null, opts, out); + } + } + } else { + printNodeLineStart(paramRole, ind, out); + out.write(_StringUtil.jQuote(node)); + printNodeLineEnd(node, out, opts); + } + } + + protected static void printNodeLineEnd(Object node, Writer out, Options opts) throws IOException { + boolean commentStared = false; + if (opts.getShowJavaClass()) { + out.write(" // "); + commentStared = true; + out.write(_ClassUtil.getShortClassNameOfObject(node, true)); + } + if (opts.getShowLocation() && node instanceof ASTNode) { + if (!commentStared) { + out.write(" // "); + commentStared = true; + } else { + out.write("; "); + } + ASTNode tObj = (ASTNode) node; + out.write("Location " + tObj.beginLine + ":" + tObj.beginColumn + "-" + tObj.endLine + ":" + tObj.endColumn); + } + out.write('\n'); + } + + private static void printNodeLineStart(ParameterRole paramRole, String ind, Writer out) throws IOException { + out.write(ind); + if (paramRole != null) { + out.write("- "); + out.write(paramRole.toString()); + out.write(": "); + } + } + + public static class Options { + + private final static Options DEFAULT_INSTANCE = new Options(); + + private boolean showJavaClass = true; + private boolean showConstantValue = false; + private boolean showLocation = false; + + public boolean getShowJavaClass() { + return showJavaClass; + } + + public void setShowJavaClass(boolean showJavaClass) { + this.showJavaClass = showJavaClass; + } + + public boolean getShowConstantValue() { + return showConstantValue; + } + + public void setShowConstantValue(boolean showConstantValue) { + this.showConstantValue = showConstantValue; + } + + public boolean getShowLocation() { + return showLocation; + } + + public void setShowLocation(boolean showLocation) { + this.showLocation = showLocation; + } + + } + + private static void p(Object obj) { + System.out.println(obj); + } + + public static class InvalidASTException extends RuntimeException { + + public InvalidASTException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidASTException(String message) { + super(message); + } + + } +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java new file mode 100644 index 0000000..7379e28 --- /dev/null +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.freemarker.core; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.apache.freemarker.core.ASTPrinter.Options; +import org.apache.freemarker.core.util._StringUtil; +import org.apache.freemarker.test.TestUtil; +import org.apache.freemarker.test.FileTestCase; + +public class ASTTest extends FileTestCase { + + public ASTTest(String name) { + super(name); + } + + public void test1() throws Exception { + testAST("ast-1"); + } + + public void testRange() throws Exception { + testAST("ast-range"); + } + + public void testAssignments() throws Exception { + testAST("ast-assignments"); + } + + public void testBuiltins() throws Exception { + testAST("ast-builtins"); + } + + public void testStringLiteralInterpolation() throws Exception { + testAST("ast-strlitinterpolation"); + } + + public void testWhitespaceStripping() throws Exception { + testAST("ast-whitespacestripping"); + } + + public void testMixedContentSimplifications() throws Exception { + testAST("ast-mixedcontentsimplifications"); + } + + public void testMultipleIgnoredChildren() throws Exception { + testAST("ast-multipleignoredchildren"); + } + + public void testNestedIgnoredChildren() throws Exception { + testAST("ast-nestedignoredchildren"); + } + + public void testLocations() throws Exception { + testASTWithLocations("ast-locations"); + } + + private void testAST(String testName) throws FileNotFoundException, IOException { + testAST(testName, null); + } + + private void testASTWithLocations(String testName) throws FileNotFoundException, IOException { + Options options = new Options(); + options.setShowLocation(true); + testAST(testName, options); + } + + private void testAST(String testName, Options ops) throws FileNotFoundException, IOException { + final String templateName = testName + ".ftl"; + assertExpectedFileEqualsString( + testName + ".ast", + ASTPrinter.getASTAsString(templateName, + TestUtil.removeFTLCopyrightComment( + normalizeLineBreaks( + loadTestTextResource( + getTestFileURL( + getExpectedContentFileDirectoryResourcePath(), templateName))) + ), ops)); + } + + private String normalizeLineBreaks(final String s) throws FileNotFoundException, IOException { + return _StringUtil.replace(s, "\r\n", "\n").replace('\r', '\n'); + } + +}
