微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用作JSF值的Java记录

如何解决用作JSF值的Java记录

我正在使用Java 15和JSF 2.3以及PrimeFaces 8开发一个简单的JSF Web应用程序(主要用于学习),并且正在使用一个简单的Java记录对实体进行建模。该应用程序不使用任何数据库

我的问题是这样的xhtml页面中是否可以使用java记录作为值

    <p:column headerText="Id">
        <h:outputText value="#{car.randomId}" />
    </p:column>

因为我收到以下错误 javax.el.PropertyNotFoundException: The class 'com.company.Car' does not have the property 'id'.。 我尝试放入car.year(),但是没有用。 记录的定义是这样

public record Car (String randomId,String randomBrand,int randomYear,String randomColor,int randomPrice,boolean randomSoldState) {
}

在pom.xml中,我正在使用以下api

        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-api</artifactId>
            <version>8.0.0</version>
            <scope>provided</scope>
        </dependency>

谢谢您的帮助!

解决方法

从技术上讲,问题不在JSF中,而在EL中。异常的程序包名称已经暗示了这一点:javax.el.PropertyNotFoundException。使用的EL版本尚无法识别Java记录。 Jakarta EE 8与Java 8联系在一起,但是Java Records功能是在Java 14中引入的。从理论上讲,它最早只能在与Java 14相关的Jakarta EE版本相关的EL版本中得到本机支持。因为Java记录只能用作“预览功能”(因此默认情况下根本没有启用)。

回到您的具体问题,使用#{car.randomId()}中的方法表达式语法确实在WildFly 21上对我有用。在任何情况下,始终可以使用自定义ELResolver自定义EL解析。这是一个启动示例,它基于Class#isRecord()检查记录并收集通过Class#getRecordComponents()可用的字段作为属性:

public class RecordELResolver extends ELResolver {

    private static final Map<Class<?>,Map<String,PropertyDescriptor>> RECORD_PROPERTY_DESCRIPTOR_CACHE = new ConcurrentHashMap<>();

    private static boolean isRecord(Object base) {
        return base != null && base.getClass().isRecord();
    }
    
    private static Map<String,PropertyDescriptor> getRecordPropertyDescriptors(Object base) {
        return RECORD_PROPERTY_DESCRIPTOR_CACHE
            .computeIfAbsent(base.getClass(),clazz -> Arrays
                .stream(clazz.getRecordComponents())
                .collect(Collectors
                    .toMap(RecordComponent::getName,recordComponent -> {
                        try {
                            return new PropertyDescriptor(recordComponent.getName(),recordComponent.getAccessor(),null);
                        }
                        catch (IntrospectionException e) {
                            throw new IllegalStateException(e);
                        }
                    })));
    }
    
    private static PropertyDescriptor getRecordPropertyDescriptor(Object base,Object property) {
        PropertyDescriptor descriptor = getRecordPropertyDescriptors(base).get(property);
        
        if (descriptor == null) {
            throw new PropertyNotFoundException("The record '" + base.getClass().getName() + "' does not have the field '" + property + "'.");
        }

        return descriptor;
    }

    @Override
    public Object getValue(ELContext context,Object base,Object property) {
        if (!isRecord(base) || property == null) {
            return null;
        }

        PropertyDescriptor descriptor = getRecordPropertyDescriptor(base,property);

        try {
            Object value = descriptor.getReadMethod().invoke(base);
            context.setPropertyResolved(base,property);
            return value;
        }
        catch (Exception e) {
            throw new ELException(e);
        }
    }

    @Override
    public Class<?> getType(ELContext context,property);
        context.setPropertyResolved(true);
        return descriptor.getPropertyType();
    }

    @Override
    public Class<?> getCommonPropertyType(ELContext context,Object base) {
        if (!isRecord(base)) {
            return null;
        }

        return String.class;
    }

    @Override
    public boolean isReadOnly(ELContext context,Object property) {
        if (!isRecord(base)) {
            return false;
        }

        getRecordPropertyDescriptor(base,property); // Forces PropertyNotFoundException if necessary.
        context.setPropertyResolved(true);
        return true;
    }

    @Override
    public void setValue(ELContext context,Object property,Object value) {
        if (!isRecord(base)) {
            return;
        }

        throw new PropertyNotWritableException("Java Records are immutable");
    }

    @Override
    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context,Object base) {
        if (!isRecord(base)) {
            return null;
        }

        Map rawDescriptors = getRecordPropertyDescriptors(base);
        return rawDescriptors.values().iterator();
    }

}

要使其正常工作,请在faces-config.xml中进行如下注册:

<application>
    <el-resolver>com.example.RecordELResolver</el-resolver>
</application>

实际工作是通过getValue()方法完成的。它基本上找到java.lang.reflect.Method代表Java记录的访问者并调用它。

也就是说,Java记录不适合替代功能强大的JavaBean,主要是因为Java记录是不可变的。因此,它们不能用作真实(JPA)实体,因为它们应该是可变的。 Java记录最多可用作DTO。

,

在深入研究堆栈跟踪并检查了用于读取属性的代码之后,目前看来,从java记录读取属性的操作似乎尚未实现。

也许是将来的版本。

请注意,一旦找到有关此主题的相关信息,我将立即更新答案。

更新8.11.2020 不幸的是,我对记录的范围有误解。

在实际应用中,我的实体将是JPA实体。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?