/** * Adapts a map to a TemplateHashModelEx using an appropriate simple adapter, normally * DefaultMapAdapter (or SimpleMapModel for BeansWrapper compatibility). * <p> * The ObjectWrapper is expected to implement at least ObjectWrapperWithAPISupport. * <p> * WARN: If impossible, it will duplicate the map using SimpleHash; but because this may result * in loss of ordering, a log warning will be printed. */ public static TemplateHashModelEx makeSimpleMapAdapter(Map<?, ?> map, ObjectWrapper objectWrapper, boolean permissive) throws TemplateModelException { // COMPATIBILITY MODE: check if exactly BeansWrapper, or a class that we know extends it WITHOUT extending DefaultObjectWrapper if (objectWrapper instanceof ScipioBeansWrapper || BeansWrapper.class.equals(objectWrapper.getClass())) { return new SimpleMapModel(map, (BeansWrapper) objectWrapper); } else if (objectWrapper instanceof ObjectWrapperWithAPISupport) { return DefaultMapAdapter.adapt(map, (ObjectWrapperWithAPISupport) objectWrapper); } else { if (permissive) { Debug.logWarning("Scipio: adaptSimpleMap: Unsupported Freemarker object wrapper (expected to implement ObjectWrapperWithAPISupport or BeansWrapper); forced to adapt map" + " using SimpleHash; this could cause loss of map insertion ordering; please switch renderer setup to a different ObjectWrapper", module); return new SimpleHash(map, objectWrapper); } else { throw new TemplateModelException("Tried to wrap a Map using an adapter class," + " but our ObjectWrapper does not implement ObjectWrapperWithAPISupport or BeansWrapper" + "; please switch renderer setup to a different ObjectWrapper"); } } }
/** * Converts map to a simple wrapper, if applicable, by rewrapping * known complex map wrappers that implement <code>WrapperTemplateModel</code>. * <p> * If the specified ObjectWrapper is a BeansWrapper, this forces rewrapping as a SimpleMapModel. * If it isn't we assume caller specified an objectWrapper that will rewrap the map with * a simple model (we have no way of knowing). * <p> * WARN: Bypasses auto-escaping for complex maps; caller must decide how to handle * (e.g. the object wrapper used to rewrap the result). * Other types of maps are not altered. * * @deprecated don't use */ @Deprecated private static TemplateHashModel toSimpleMapRewrapAdapters(TemplateModel object, ObjectWrapper objectWrapper) throws TemplateModelException { if (object instanceof SimpleMapModel || object instanceof BeanModel || object instanceof DefaultMapAdapter) { // Permissive Map<?, ?> wrappedObject = (Map<?, ?>) ((WrapperTemplateModel) object).getWrappedObject(); if (objectWrapper instanceof BeansWrapper) { // Bypass the beanswrapper wrap method and always make simple wrapper return new SimpleMapModel(wrappedObject, (BeansWrapper) objectWrapper); } else { // If anything other than BeansWrapper, assume caller is aware and his wrapper will create a simple map return (TemplateHashModel) objectWrapper.wrap(wrappedObject); } } else if (object instanceof TemplateHashModel) { return (TemplateHashModel) object; } else { throw new TemplateModelException("object is not a recognized map type"); } }
@Override public TemplateModel wrap(final Object obj) throws TemplateModelException { if (obj instanceof Config) { ConfigObject config = ((Config) obj).root(); return DefaultMapAdapter.adapt(config.unwrapped(), (ObjectWrapperWithAPISupport) wrapper); } if (obj instanceof Request) { Map<String, Object> req = ((Request) obj).attributes(); return DefaultMapAdapter.adapt(req, (ObjectWrapperWithAPISupport) wrapper); } if (obj instanceof Session) { Session session = (Session) obj; if (session.isDestroyed()) { return wrapper.wrap(null); } Map<String, String> hash = session.attributes(); return DefaultMapAdapter.adapt(hash, (ObjectWrapperWithAPISupport) wrapper); } return wrapper.wrap(obj); }
@Test public void testSuccess() { Map<String, Object> root = new HashMap<>(); root.put("url", "toto"); root.put("componentKey", "tata"); root.put("severity", Severity.BLOCKER); root.put("message", "titi"); root.put("ruleKey", "ici"); root.put("ruleLink", "http://myserver/coding_rules#rule_key=ici"); Assertions.assertThat(print(Collections.singletonList(DefaultMapAdapter.adapt(root, null)))).isEqualTo(":no_entry: [titi](toto) [:blue_book:](http://myserver/coding_rules#rule_key=ici)"); }
@Override public Object exec(@SuppressWarnings("rawtypes") List arguments) throws TemplateModelException { ExecutionStatistics.get().begin(NAME); if (arguments.size() == 0) throw new TemplateModelException("Freemarker function "+NAME+"expects a Map<String, String> as a parameter."); final Object arg0 = arguments.get(0); if (null == arg0) { return null; } if (!(arg0 instanceof DefaultMapAdapter)) { LOG.warning("Expected a Freemarker's DefaultMapAdapter, was: " + arg0.getClass()); return null; } DefaultMapAdapter mapModel = (DefaultMapAdapter) arg0; Map<String, String> map = (Map<String, String>) mapModel.getWrappedObject(); ObjectMapper mapper = new ObjectMapper(); try { String json = mapper.writeValueAsString(map); return json; } catch (JsonProcessingException e) { throw new TemplateModelException("Couldn't convert given map to a JSON."); } finally { ExecutionStatistics.get().end(NAME); } }