Cannot invoke "javax.swing.text.html.CSS$CssValue.parseCssValue(String)" because "conv" is null

Answered

class:

public class CodeTextPane extends JTextPane implements RefreshColorComponent {
    private static final Logger log = LoggerFactory.getLogger(CodeTextPane.class);
    private static Code2HtmlConverter converter = new PrismCode2HtmlConverter();
    private static final String DEFAULT_LANGUAGE = "markdown";
    private String language;
    private String originText;
    private String template;
    private HTMLEditorKit editorKit;

    public CodeTextPane(String content, String language) {
        this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        this.originText = content;
        this.template = ThemeUtil.loadCodeGeneralTemplate();
        this.template = SchemaColorUtil.applySchemaColor(this.template);
        this.setEditable(false);
        this.setFocusable(true);
        this.setContentType("text/html");
        this.setCursor(Cursor.getPredefinedCursor(2));

        if (StringUtils.isBlank(language)) {
            language = this.getDefaultLanguage();
        } else {
            language = language.trim();
        }

        this.language = language;
        this.editorKit = new HTMLEditorKit();
        this.setEditorKit(this.editorKit);
        this.setFont(FontUtil.loadFont("font/SourceHanSansCN-Regular.otf", Font.PLAIN, 14f));
    }

    public void scrollRectToVisible(Rectangle aRect) {
    }

    private String buildText(String text, String language) {
        if (StringUtils.isBlank(this.template)) {
            return text;
        } else {
            language = language.toLowerCase(Locale.ROOT);
            text = StringUtils.stripEnd(text, "\n\t ");
            String html = converter.convert(text, language);
            if (html == null) {
                html = StringUtil.escapeXmlEntities(text);
            }

            EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme();
            Font font = editorColorsScheme.getFont(EditorFontType.PLAIN);
            String fontFamily = font.getFamily();
            Color editorColor = ColorUtil.getEditorBackgroundColor();
            String editorBackgroundColor = String.format("#%02x%02x%02x", editorColor.getRed(), editorColor.getGreen(), editorColor.getBlue());
            return this.template.replace("{{fontFamily}}", fontFamily).replace("{{content}}", html).replace("{{language}}", language).replace("{{background}}", editorBackgroundColor);
        }
    }

    public Color getSelectionColor() {
        return PluginColor.MARK_DOWN_CODE_SELECT_BG_COLOR;
    }

    public void setText(String text) {
        this.originText = text;
        text = this.buildText(text, this.language);

        try {
            super.setText(text);
        } catch (Exception e) {
            log.error("", e);
        }
    }


    public String getText() {
        return this.originText;
    }

    private String getDefaultLanguage() {
        return DEFAULT_LANGUAGE;
    }

    public void setLanguage(String language) {
        if (StringUtils.isNotBlank(language)) {
            this.language = language.trim();
        }
    }

    public void refreshColor(EditorColorsScheme scheme, Color themeColor) {
        this.template = ThemeUtil.loadCodeGeneralTemplate();
        this.template = SchemaColorUtil.applySchemaColor(this.template);
        this.setText(this.getText());
        this.invalidate();
        this.repaint();
    }
}

Executable Codes:

String content = "\npublic class QuickSort {\n";
String language = "java";
CodeTextPane editorTextField = new CodeTextPane(content, language);

        if (StringUtils.isNotBlank(content)) {
            editorTextField.setLanguage(language);
            editorTextField.setText(content);
        }
 

Error location:  editorTextField.setText(content);,

The specific location of calling the CodeTextPane class:

public void setText(String text) {
        this.originText = text;
        text = this.buildText(text, this.language);

        try {
            super.setText(text);
        } catch (Exception e) {
            log.error("", e);
        }
    }

super.setText(text) error:

Cannot invoke "javax.swing.text.html.CSS$CssValue.parseCssValue(String)" because "conv" is null

Explanation: Content is a code that, when converted to HTML, highlights the code when displayed. Strangely, there was no error message the first time, but on the second time, when switching the session to the second time, there was an error message. The first time the project started, there was no error message

Environment: jdk: jbr_jcef 21, IntelliJ IDEA 2024.2.4 (Ultimate Edition) error ,gradle the latest version

jdk: jbr_jcef 17, IntelliJ IDEA 2023.1-2024.1 (Ultimate Edition) Normal

 

Thank you, thank you for your hard work. I hope to get a solution because the plugin is in the latest version of idea2024.2 and there is this error. I want to continue developing it. Is there any way to solve it

0
6 comments

Not sure this error is related to IJ Platform, looks like some Swing issue with your code maybe?
Have you tried using com.intellij.ui.components.JBHtmlPane provided by platform instead?

0

hello,Yann Cebron,com.intellij.ui.components.JBHtmlPane,I tried this too, but it's still the same problem

Converting code to HTML is correct because it can be rendered correctly when opened directly in a browser. Otherwise, IDEA would have been displayed normally from January 2023 to January 2024, but this issue would have occurred in February 2024. There is really no way to solve this problem. I hope I can provide more relevant information

0

hello,Yann CebronI wrote a small demo and recorded the error messages on it. You can take a look

public class RefactorChatWindow implements DumbAware, ToolWindowFactory 

@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {

JFrame frame = new JFrame("CodeContentCellHighlightComponent Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        JPanel parentComponent = new JPanel(new BorderLayout());
        parentComponent.setPreferredSize(new Dimension(800, 600));
        String codeContent = "\npublic class QuickSort {\n    public static void main(String[] args) {\n        System.out.println(\"Hello World!\");\n    }\n}";
        String language = "java";
        CodeContentCellHighlightComponent highlightComponent = new CodeContentCellHighlightComponent(project, codeContent, language, parentComponent, 800, true);
        parentComponent.add(highlightComponent, BorderLayout.CENTER);
        frame.getContentPane().add(parentComponent);
        frame.setVisible(true);

CodeContentCellHighlightComponent

    private final Project project;
    private final ToolbarPane toolbarPane;
    private final JComponent parentComponent;
    Dimension parentComponentSize;
    private final CodeJBHtmlPane editorTextField
    private JScrollPane jbScrollPane;
    private String lang;
    @Getter
    private String content;

    public CodeContentCellHighlightComponent(Project project, String content, String language, JComponent parentComponent, int limitCodeBlockHeight, boolean isOwner) {
        super(new BorderLayout());
        this.project = project;
        this.lang = language;
        this.content = content;

        this.parentComponent = parentComponent;
        this.parentComponentSize = parentComponent.getSize();
        // 创建核心显示组件
        content = "\npublic class QuickSort {\n";
        language = "java";
        this.editorTextField = new CodeJBHtmlPane(content, language);
        // 创建滚动条面板
        createJScrollPaneUI();
        this.add(jbScrollPane, BorderLayout.CENTER);
        // 渲染markdown内容
        if (StringUtils.isNotBlank(content)) {
            editorTextField.setLanguage(language);
            editorTextField.setText(content);
        }
        super.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                CodeContentCellHighlightComponent.this.revalidate();
                CodeContentCellHighlightComponent.this.repaint();
            }
        });
    }

private void createJScrollPaneUI() {
    jbScrollPane = new JBScrollPane(editorTextField);
    jbScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    jbScrollPane.setMinimumSize(new Dimension(500, 1000));
    jbScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    jbScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
}

CodeJBHtmlPane

public class CodeJBHtmlPane extends JBHtmlPane implements RefreshColorComponent {
    private static final Logger log = LoggerFactory.getLogger(CodeTextPane.class);
    private static Code2HtmlConverter converter = new PrismCode2HtmlConverter();
    private static final String DEFAULT_LANGUAGE = "markdown";
    private String language;
    private String originText;
    private String template;

    public CodeJBHtmlPane(String content, String language) {
        super(JBHtmlPaneStyleConfiguration.builder().build(), JBHtmlPaneConfiguration.builder().build()); // 使用默认的配置
        // 初始化设置
        this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        this.originText = content;
        this.template = ThemeUtil.loadCodeGeneralTemplate();
        this.template = SchemaColorUtil.applySchemaColor(this.template);
        this.setEditable(false);
        this.setFocusable(true);
        this.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));

        if (StringUtils.isBlank(language)) {
            language = this.getDefaultLanguage();
        } else {
            language = language.trim();
        }

        this.language = language;
        this.setFont(FontUtil.loadFont("font/SourceHanSansCN-Regular.otf", Font.PLAIN, 14f));
        this.setText(content);
    }

    @Override
    public void scrollRectToVisible(Rectangle aRect) {
        // 此方法可留空,保持默认行为
    }

    private String buildText(String text, String language) {
        if (StringUtils.isBlank(this.template)) {
            return text;
        } else {
            language = language.toLowerCase(Locale.ROOT);
            text = StringUtils.stripEnd(text, "\n\t ");
            String html = converter.convert(text, language);
            if (html == null) {
                html = StringUtil.escapeXmlEntities(text);
            }

            EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme();
            Font font = editorColorsScheme.getFont(EditorFontType.PLAIN);
            String fontFamily = font.getFamily();
            Color editorColor = UIUtil.getEditorPaneBackground();
            String editorBackgroundColor = String.format("#%02x%02x%02x", editorColor.getRed(), editorColor.getGreen(), editorColor.getBlue());
            return this.template.replace("{{fontFamily}}", fontFamily)
                    .replace("{{content}}", html)
                    .replace("{{language}}", language)
                    .replace("{{background}}", editorBackgroundColor);
        }
    }

    @Override
    public Color getSelectionColor() {
        return PluginColor.MARK_DOWN_CODE_SELECT_BG_COLOR;
    }

    @Override
    public void setText(String text) {
        this.originText = text;
        String htmlContent = this.buildText(text, this.language);

        try {
            super.setText(htmlContent);
        } catch (Exception e) {
            log.error("Error setting text in CodeTextPane", e);
        }
    }

    @Override
    public String getText() {
        return this.originText;
    }

    private String getDefaultLanguage() {
        return DEFAULT_LANGUAGE;
    }

    public void setLanguage(String language) {
        if (StringUtils.isNotBlank(language)) {
            this.language = language.trim();
        }
    }

    public void refreshColor(EditorColorsScheme scheme, Color themeColor) {
        this.template = ThemeUtil.loadCodeGeneralTemplate();
        this.template = SchemaColorUtil.applySchemaColor(this.template);
        this.setText(this.getText());
        this.invalidate();
        this.repaint();
    }
}
 

0

Hi! It looks like your content might contain CSS with some property, which is not recognized by the Swing HTML renderer and it causes the NPE. Can you please check what is the value of the key argument in the getInternalCSSValue when the NPE happen. You can set an exception breakpoint, which will stop the debugger when the exception is thrown and you should be able to check why valueConvertor.get(key) returns null

0

this.template = ThemeUtil.loadCodeGeneralTemplate(); 
this.template = SchemaColorUtil.applySchemaColor(this.template);

hi, Piotr Tomiak,thank you. I tried to remove the border radius: 8px from the generated template to solve this problem. It seems that the new version cannot recognize this attribute, which is causing the issue

0

it would be good to fix in JBR

public class CSS { …
/**
 * Gets the internal CSS representation of <code>value</code> which is
 * a CSS value of the CSS attribute named <code>key</code>. The receiver
 * should not modify <code>value</code>, and the first <code>count</code>
 * strings are valid.
 */
Object getInternalCSSValue(CSS.Attribute key, String value) {
    CssValue conv = (CssValue) valueConvertor.get(key);
    Object r = conv.parseCssValue(value);
    return r != null ? r : conv.parseCssValue(key.getDefaultValue());
}

}

to 

Object getInternalCSSValue(CSS.Attribute key, String value) {
    CssValue conv = (CssValue) valueConvertor.get(key);
    if (conv == null) return null
    Object r = conv.parseCssValue(value);
    return r != null ? r : conv.parseCssValue(key.getDefaultValue());
}


Till that you can use it ONLY IN CHILD StyleSheets, created by call `StyleSheetUtil`. They have the magic 
StyleSheet().patchAttributes()
call. 

0

Please sign in to leave a comment.