Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Provide a callback for customising Freemarker variables #8965

Closed
ohalo opened this issue Apr 21, 2017 · 35 comments
Closed

Provide a callback for customising Freemarker variables #8965

ohalo opened this issue Apr 21, 2017 · 35 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@ohalo
Copy link

ohalo commented Apr 21, 2017

boot automatic configuration freemarker lack freemarkerVariables

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 21, 2017
@wilkinsona
Copy link
Member

What do you mean by "freemarkerVariables"? Can you please show what you're currently having to configure that the auto-configuration should be able to configure for you?

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 21, 2017
@ohalo

This comment was marked as duplicate.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 25, 2017
@ohalo

This comment was marked as duplicate.

@ohalo

This comment was marked as duplicate.

@ohalo

This comment was marked as duplicate.

@ohalo
Copy link
Author

ohalo commented Apr 25, 2017

but FreeMarkerConfigurationFactory has freemarkerVariables,i need it

@ohalo

This comment was marked as duplicate.

@wilkinsona
Copy link
Member

Ok, so you'd like to be able to set the freemarkerVariables property on either the auto-configured FreeMarkerConfigurationFactoryBean or on the auto-configured FreeMarkerConfigurer bean, correct? Both are subclasses of FreeMarkerConfigurationFactory.

What variables do you want to be able to set? Can you please provide some specific examples? Please note that values other than maps, lists and scalar values are not well-suited to being set via application.properties.

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Apr 25, 2017
@ohalo

This comment was marked as outdated.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 28, 2017
@ohalo

This comment was marked as duplicate.

@wilkinsona

This comment was marked as resolved.

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Apr 28, 2017
@ohalo
Copy link
Author

ohalo commented Apr 28, 2017


@ConfigurationProperties(prefix = "freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {

	public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";

	public static final String DEFAULT_PREFIX = "";

	public static final String DEFAULT_SUFFIX = ".ftl";

	/**
	 * Well-known FreeMarker keys which will be passed to FreeMarker's Configuration.
	 */
	private Map<String, String> settings = new HashMap<String, String>();

        private Map<String, String> freemarkerVariables = new HashMap<String, String>();

and configuration is

#freemarker
freemarker:
  settings:
    object_wrapper: com.control.back.halo.basic.utils.FreemarkerObjectWrapper
    datetime_format: yyyy-MM-dd HH:mm:ss
    date_format: yyyy-MM-dd
    time_format: HH:mm:ss    
  freemarker-variables:
    base: http://127.0.0.1:80

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 28, 2017
@ohalo
Copy link
Author

ohalo commented Apr 28, 2017

in FreeMarkerAutoConfiguration ,and join factory.setFreemarkerVariables(this.properties.getFreemarkerVariables());

protected static class FreeMarkerConfiguration {

      @Autowired
      protected FreeMarkerProperties properties;

      protected void applyProperties(FreeMarkerConfigurationFactory factory) {
          factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());
          factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());
          factory.setDefaultEncoding(this.properties.getCharsetName());
          Properties settings = new Properties();
          settings.putAll(this.properties.getSettings());
          factory.setFreemarkerSettings(settings);
          factory.setFreemarkerVariables(this.properties.getFreemarkerVariables());
      }

  }

@ohalo

This comment was marked as outdated.

@wilkinsona
Copy link
Member

The formatting is much better, thank you. Unfortunately, it's not really what it was looking for.

You've shown how what you're asking for could be implemented in Spring Boot and I already know how to do that. What I don't know is what values you want to set in freemarkerVariables. You've shown one example which is setting base to http://127.0.0.1:80. What other variables would you like to be able to set and what values might they have? I am asking because the values in freemarkerVariables can be anything (it's a Map<String, Object>) and application.properties or application.yml aren't a good way to set some types of Object. As I said above, it's only suited to setting maps, lists and scalar values.

If you want to configure something that's more complex, or you just want to do this without an enhancement to Spring Boot, then registering a BeanPostProcessor for the FreeMarkerConfigurer or FreeMarkerConfigurationFactoryBean may be what you need to do.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Apr 28, 2017
@wo8335224
Copy link


@Configuration
public class FreemarkerConfiguration extends FreeMarkerAutoConfiguration.FreeMarkerWebConfiguration {
	@Value("${ctx.static}")
	private String ctx;
	@Value("${ctx.custom}")
	private Integer custom;

	@Override
	public FreeMarkerConfigurer freeMarkerConfigurer() {
		FreeMarkerConfigurer configurer = super.freeMarkerConfigurer();

		Map<String, Object> sharedVariables = new HashMap<>();
		if (custom != null && custom == 1) {
			sharedVariables.put("sctx", ctx);
		}
		configurer.setFreemarkerVariables(sharedVariables);
		return configurer;
	}
}

workd for me

@ohalo

@bianjp
Copy link

bianjp commented Mar 2, 2018

Spring Boot 2.0 breaks the solution provided by @wo8335224, as FreeMarkerWebConfiguration is replaced by FreeMarkerServletWebConfiguration, which is unfortunately package-private and thus cannot be subclassed.

A currently working solution is to configure freemarker.template.Configuration bean:

@Configuration
public class FreemarkerConfig {
    public FreemarkerConfig(freemarker.template.Configuration configuration) throws TemplateModelException {
        configuration.setSharedVariable("name", "whatever type of value");
    }
}

Internally FreeMarkerConfigurer#setFreemarkerVariables delegates its work to freemarker.template.Configuration#setAllSharedVariables.

@satahippy
Copy link

Hey @bianjp !

Yes, you can do this, but you'll lose some auto-configuration.
So better use BeanPostProcessor.

@Component
class FreeMarkerPostProcessor : BeanPostProcessor {
    override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any {
        if (bean is FreeMarkerConfigurer) {
            bean.setFreemarkerVariables(mapOf(
                    "globalVar" to "globalVarValue"
            ))
        }
        return bean
    }
}

@kaliatech
Copy link

kaliatech commented Oct 9, 2018

Thanks @satahippy. Java version:

@Configuration
public class CustomFreeMarkerConfig implements BeanPostProcessor {

    Object sharedWithAllFreeMarkerTemplatesObj = new Object();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
    throws BeansException {
        if (bean instanceof FreeMarkerConfigurer) {
            FreeMarkerConfigurer configurer = (FreeMarkerConfigurer) bean;
            Map<String, Object> sharedVariables = new HashMap<>();
            sharedVariables.put("globalVar", sharedWithAllFreeMarkerTemplatesObj);
            configurer.setFreemarkerVariables(sharedVariables);
        }
        return bean;
    }
}

[edit: my original comment confused Before/After Initialization)

I feel like there should be some easier, built-in way, of doing this, but I haven't found it yet. Related question on StackOverflow: https://stackoverflow.com/questions/52730368/how-to-make-globally-shared-objects-available-to-freemarker-templates-in-spring

@wilkinsona wilkinsona changed the title boot automatic configuration freemarker lack freemarkerVariables Provide a callback from customising the auto-configured FreeMarkerConfigurer Feb 6, 2019
@bclozel bclozel added this to the 2.2.x milestone Feb 6, 2019
@wilkinsona wilkinsona changed the title Provide a callback from customising the auto-configured FreeMarkerConfigurer Provide a callback for customising the auto-configured FreeMarkerConfigurer Feb 6, 2019
@wilkinsona wilkinsona removed the status: on-hold We can't start working on this issue yet label Feb 6, 2019
@snicoll snicoll added the for: team-attention An issue we'd like other members of the team to review label May 20, 2019
@wilkinsona wilkinsona removed the for: team-attention An issue we'd like other members of the team to review label May 29, 2019
@snicoll snicoll added the status: blocked An issue that's blocked on an external project change label May 29, 2019
@snicoll

This comment was marked as outdated.

@snicoll snicoll modified the milestones: 2.2.x, 2.x Jul 16, 2019
@mauromol
Copy link

+1 for this. Today I encountered the same need.

@philwebb philwebb modified the milestones: 2.x, General Backlog Aug 19, 2022
@wilkinsona
Copy link
Member

I don't think this needs to be blocked on the Framework issue. While allowing the variables to be amended could be useful, being able to set them (overwriting anything already set) would still be a step forwards. As and when there's a Framework API that allows the variables to be amended, that would be an additional benefit of a customizer callback in Boot.

@wilkinsona wilkinsona removed the status: blocked An issue that's blocked on an external project change label Nov 29, 2023
@wilkinsona wilkinsona modified the milestones: General Backlog, 3.x Nov 29, 2023
@snicoll snicoll self-assigned this Aug 2, 2024
@snicoll snicoll changed the title Provide a callback for customising the auto-configured FreeMarkerConfigurer Provide a callback for customising Freemarker variables Aug 2, 2024
@snicoll snicoll modified the milestones: 3.x, 3.4.0-M2 Aug 2, 2024
@snicoll snicoll closed this as completed in a2fafa1 Aug 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests