2015-06-07 4 views
1

Когда я использую UUID#randomUUID() (который использует SecureRandom) или RandomStringUtils#randomAlphabetic(int) (который использует Random) для генерации идентификатора компонента для проверки работоспособности HtmlInputText. Если вместо этого я устанавливаю идентификатор компонента с использованием произвольной жестко запрограммированной строки (например, «C5d682a6f»), то проверка выполняется так, как ожидалось. Вот код:JSF Validators не работают, если Random или SecureRandom используются для генерации идентификатора компонента.

import org.apache.commons.lang3.RandomStringUtils; 
import java.util.UUID; 
import javax.faces.component.html.HtmlInputText; 
import javax.faces.component.html.HtmlMessage; 
import javax.faces.component.html.HtmlPanelGrid; 

@Model 
public class LoginBean 
{ 
    private HtmlPanelGrid panelGrid; 
    private String email; 
    @PostConstruct void initialize() 
    { 
     FacesContext facesContext = FacesContext.getCurrentInstance(); 
     String componentId; 
     componentId = "C" + UUID.randomUUID().toString().substring(0, 8); // Yields something like "C5d682a6f", which should be fine, yet breaks validation. 
     //componentId = RandomStringUtils.randomAlphabetic(8);    // Yields something like "zxYBcUYM", which should be fine, yet breaks validation. 
     //componentId = "C5d682a6f";          // Hard-coding the same exact kind of string generated by UUID#randomUUID() works fine. 
     //componentId = "zxYBcUYM";           // Hard-coding the same exact kind of string generated by RandomStringUtils#randomAlphabetic(int) 

     HtmlInputText emailFieldComponent = (HtmlInputText)facesContext.getApplication().createComponent(
      facesContext, 
      HtmlInputText.COMPONENT_TYPE, 
      "javax.faces.Text" 
     ); 
     emailFieldComponent.setId(componentId); 
     emailFieldComponent.setValueExpression(
      "value", 
      facesContext.getApplication().getExpressionFactory().createValueExpression(
       facesContext.getELContext(), 
       "#{loginBean.email}", 
       String.class 
      ) 
     ); 

     // The following validators stop working if UUID#randomUUID() or 
     // RandomStringUtils#randomAlphabetic(int) are used to generate componentId. 
     emailFieldComponent.setRequired(true); 
     emailFieldComponent.addValidator(new EmailValidator()); 

     HtmlMessage message = (HtmlMessage)facesContext.getApplication().createComponent(
      facesContext, 
      HtmlMessage.COMPONENT_TYPE, 
      "javax.faces.Message" 
     ); 
     message.setFor(componentId); 

     panelGrid = (HtmlPanelGrid)facesContext.getApplication().createComponent(
      facesContext, 
      HtmlPanelGrid.COMPONENT_TYPE, 
      "javax.faces.Grid" 
     ); 
     panelGrid.setColumns(2); 
     panelGrid.getChildren().add(emailFieldComponent); 
     panelGrid.getChildren().add(message); 
    } 
} 

Любые идеи о том, почему это так? Я просто нужно ComponentID, чтобы быть произвольная строка генерируется во время выполнения и в соответствии со следующими конвенциями (от UIComponent#setId(String) JavaDoc):

компонентов идентификаторы должны соблюдать следующие ограничения синтаксиса:

Must not be a zero-length String. 
First character must be a letter or an underscore ('_'). 
Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-'). 

компонентов идентификаторы должны также соблюдать следующие семантические ограничения (заметим, что это ограничение не является обязательным для реализации SETID()):

The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer. 

Моя среда разработки Mojarra 2.2.6-jbossorg-4 на Wildfly 8.1.0.Final.

EDIT:

Таким образом, кажется, что любая попытка создать идентификатор компонента во время выполнения вызывает проверка не произойдет.

componentId = "C" + Long.toHexString(Double.doubleToLongBits(Math.random())); 
    componentId = "C" + Long.toHexString(System.currentTimeMillis()); 
    componentId = "C" + Long.toHexString(new Date().getTime()); 
    componentId = "C" + new Date().hashCode(); 

Принимая во внимание, что идентификатор компонента известен во время компиляции, проверка достоверности происходит просто отлично.

componentId = "C" + Long.toHexString(Double.doubleToLongBits(Double.MAX_VALUE)); 

Я бы очень хотел понять, почему это так.

EDIT # 2:

следующие работы просто отлично (спасибо, BalusC), ComponentID генерируется во время выполнения, что это именно то, что мне нужно:

setId(facesContext.getViewRoot().createUniqueId()); 

Я последовал совету BalusC в и посмотрел на UIViewRoot#createUniqueId(), который выглядит, как это под капотом:

public String createUniqueId() { 
    return createUniqueId(getFacesContext(), null); 
} 

public String createUniqueId(FacesContext context, String seed) { 
    if (seed != null) { 
     return UIViewRoot.UNIQUE_ID_PREFIX + seed; 
    } else { 
     Integer i = (Integer) getStateHelper().get(PropertyKeys.lastId); 
     int lastId = ((i != null) ? i : 0); 
     getStateHelper().put(PropertyKeys.lastId, ++lastId); 
     return UIViewRoot.UNIQUE_ID_PREFIX + lastId; 
    } 
} 

Но я запутался потому, что он что указанный выше метод сохраняет новый идентификатор клиента в состоянии просмотра JSF. Он только увеличивает lastId и обновляет lastId в состоянии просмотра.

ответ

1

Идентификаторы компонентов не хранятся в состоянии просмотра JSF. Они похожи на сами компоненты, поэтому в основном запрашивают область. Только материал, который хранится в состоянии просмотра JSF, в основном имеет вид области видимости. То есть материал, который компоненты ставят/получают через метод getStateHelper(). Методы getId()/setId() этого не делают.

Когда JSF необходимо обработать запрос обратной передачи, он будет во время фазы восстановления восстанавливать представление (т. Е. Все экземпляры компонентов будут воссозданы как new UIComponent() и т. Д.), И, таким образом, компоненты будут с вашим путем получить другой идентификатор клиента. В дальнейшем JSF восстановит дерево компонентов данными из состояния представления JSF.

Затем, когда JSF необходимо обработать фазу запроса заявки, он будет извлекать параметры запроса из карты параметров запроса HTTP с использованием идентификатора клиента в качестве имени параметра. Однако, поскольку этот идентификатор клиента изменился, JSF не может найти первоначально представленные значения.

Что здесь происходит. Как решить это - это вторая. Хорошей отправной точкой является UINamingContainer#createUniqueId().

+0

Похоже, что 'UINamingContainer # createUniqueId()' получает lastId из 'StateHelper', добавляет его в j_id и увеличивает lastId помощника состояния. Я обновил свой вопрос в запросе для разъяснения (см. Редактировать № 2). –

+0

Идентификатор компонента/клиента также не должен сохраняться в состоянии просмотра. Это время, основанное на построении времени, а не на основе времени выполнения (например, теги-манипуляторы и т. Д.). – BalusC

 Смежные вопросы

  • Нет связанных вопросов^_^