image.png

    1. /*
    2. * Licensed to the Apache Software Foundation (ASF) under one
    3. * or more contributor license agreements. See the NOTICE file
    4. * distributed with this work for additional information
    5. * regarding copyright ownership. The ASF licenses this file
    6. * to you under the Apache License, Version 2.0 (the
    7. * "License"); you may not use this file except in compliance
    8. * with the License. You may obtain a copy of the License at
    9. *
    10. * http://www.apache.org/licenses/LICENSE-2.0
    11. *
    12. * Unless required by applicable law or agreed to in writing, software
    13. * distributed under the License is distributed on an "AS IS" BASIS,
    14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15. * See the License for the specific language governing permissions and
    16. * limitations under the License.
    17. */
    18. package org.apache.flink.table.runtime.generated;
    19. import java.io.Serializable;
    20. import static org.apache.flink.util.Preconditions.checkNotNull;
    21. /**
    22. * A wrapper for generated class, defines a {@link #newInstance(ClassLoader)} method
    23. * to get an instance by reference objects easily.
    24. */
    25. public abstract class GeneratedClass<T> implements Serializable {
    26. private final String className;
    27. private final String code;
    28. private final Object[] references;
    29. private transient Class<T> compiledClass;
    30. protected GeneratedClass(String className, String code, Object[] references) {
    31. checkNotNull(className, "name must not be null");
    32. checkNotNull(code, "code must not be null");
    33. checkNotNull(references, "references must not be null");
    34. this.className = className;
    35. this.code = code;
    36. this.references = references;
    37. }
    38. /**
    39. * Create a new instance of this generated class.
    40. */
    41. @SuppressWarnings("unchecked")
    42. public T newInstance(ClassLoader classLoader) {
    43. try {
    44. return compile(classLoader).getConstructor(Object[].class)
    45. // Because Constructor.newInstance(Object... initargs), we need to load
    46. // references into a new Object[], otherwise it cannot be compiled.
    47. .newInstance(new Object[] {references});
    48. } catch (Exception e) {
    49. throw new RuntimeException(
    50. "Could not instantiate generated class '" + className + "'", e);
    51. }
    52. }
    53. @SuppressWarnings("unchecked")
    54. public T newInstance(ClassLoader classLoader, Object... args) {
    55. try {
    56. return (T) compile(classLoader).getConstructors()[0].newInstance(args);
    57. } catch (Exception e) {
    58. throw new RuntimeException(
    59. "Could not instantiate generated class '" + className + "'", e);
    60. }
    61. }
    62. /**
    63. * Compiles the generated code, the compiled class will be cached in the {@link GeneratedClass}.
    64. */
    65. public Class<T> compile(ClassLoader classLoader) {
    66. if (compiledClass == null) {
    67. // cache the compiled class
    68. compiledClass = CompileUtils.compile(classLoader, className, code);
    69. }
    70. return compiledClass;
    71. }
    72. public String getClassName() {
    73. return className;
    74. }
    75. public String getCode() {
    76. return code;
    77. }
    78. public Object[] getReferences() {
    79. return references;
    80. }
    81. public Class<T> getClass(ClassLoader classLoader) {
    82. return compile(classLoader);
    83. }
    84. }
    • 所有生成的代码都是通过 newInstance方法实例化,在实例化的的过程中会使用janinoSimpleCompiler编译文本的代码生成对应的 Class 类,然后通过这个 Class类实例化对象,在这个过程中对生成的 Class类是有缓存的。
    • 在包org.apache.flink.table.planner.codegen中有生成各种code代码的 code generator 代码生成 - 图2