Permalink
Browse files

View handler that checks if there are any auto-generated IDs rendered.

  • Loading branch information...
1 parent 4ea6584 commit c83e4ab509fb5a2fbbe4f26ea43300f7199478a3 arjan.tijms committed Jun 26, 2014
Showing with 125 additions and 0 deletions.
  1. +125 −0 src/main/java/org/omnifaces/viewhandler/NoAutoGeneratedIdViewHandler.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2014 OmniFaces.
+ *
+ * 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.
+ */
+package org.omnifaces.viewhandler;
+
+import static javax.faces.component.UINamingContainer.getSeparatorChar;
+import static javax.faces.component.UIViewRoot.UNIQUE_ID_PREFIX;
+import static org.omnifaces.util.Components.getCurrentComponent;
+
+import java.io.IOException;
+
+import javax.faces.FacesException;
+import javax.faces.application.ViewHandler;
+import javax.faces.application.ViewHandlerWrapper;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextWrapper;
+import javax.faces.context.ResponseWriter;
+import javax.faces.context.ResponseWriterWrapper;
+
+/**
+ * This view handler once installed will throw an exception whenever an automatically generated id (<code>j_idt...</code>)
+ * is encountered in the rendered output.
+ * <p>
+ * Note that this does not check every component for its ID directly, but instead checks the {@link ResponseWriter} for
+ * writes to the "id" attribute. Components that write their markup in any other way won't be checked and will thus
+ * slip through.
+ *
+ * @since 2.0
+ * @author Arjan Tijms
+ */
+public class NoAutoGeneratedIdViewHandler extends ViewHandlerWrapper {
+
+ // Private constants ----------------------------------------------------------------------------------------------
+
+ private static final String ERROR_AUTO_GENERATED_ID_ENCOUNTERED =
+ "Auto generated ID '%s' encountered. Current component type: '%s'. Parent component type: '%s' with ID '%s'.";
+
+
+ // Properties -----------------------------------------------------------------------------------------------------
+
+ private ViewHandler wrapped;
+
+
+ // Constructors ---------------------------------------------------------------------------------------------------
+
+ /**
+ * Construct a new No Auto Generated Id view handler around the given wrapped view handler.
+ *
+ * @param wrapped
+ * The wrapped view handler.
+ */
+ public NoAutoGeneratedIdViewHandler(ViewHandler wrapped) {
+ this.wrapped = wrapped;
+ }
+
+
+ // Actions --------------------------------------------------------------------------------------------------------
+
+ @Override
+ public void renderView(final FacesContext context, final UIViewRoot viewToRender) throws IOException, FacesException {
+
+ final String INTERMEDIATE_ID_PREFIX = getSeparatorChar(context) + UNIQUE_ID_PREFIX;
+
+ super.renderView(new FacesContextWrapper() {
+
+ @Override
+ public void setResponseWriter(final javax.faces.context.ResponseWriter responseWriter) {
+
+ super.setResponseWriter(new ResponseWriterWrapper() {
+
+ @Override
+ public void writeAttribute(String name, Object value, String property) throws IOException {
+
+ if ("id".equals(name) && isGeneratedID(value)) {
+
+ UIComponent currentComponent = getCurrentComponent();
+ UIComponent parentComponent = currentComponent == null ? null : currentComponent.getParent();
+
+ throw new IllegalStateException(String.format(ERROR_AUTO_GENERATED_ID_ENCOUNTERED,
+ value,
+ currentComponent == null ? "<current component null>" : currentComponent.getClass().getName(),
+ parentComponent == null ? "<parent component null>" : parentComponent.getClass().getName(),
+ parentComponent == null ? "<no parent ID>" : parentComponent.getId()
+ ));
+ }
+
+ super.writeAttribute(name, value, property);
+ };
+
+ private boolean isGeneratedID(Object value) {
+ return value != null && (value.toString().startsWith(UNIQUE_ID_PREFIX) || value.toString().contains(INTERMEDIATE_ID_PREFIX));
+ }
+
+ @Override
+ public ResponseWriter getWrapped() {
+ return responseWriter;
+ }
+ });
+
+ };
+
+ @Override
+ public FacesContext getWrapped() {
+ return context;
+ }
+ } , viewToRender);
+ }
+
+ @Override
+ public ViewHandler getWrapped() {
+ return wrapped;
+ }
+
+}

0 comments on commit c83e4ab

Please sign in to comment.