Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Java 22 features to PL/Java user code #480

Merged
merged 4 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions pljava-api/src/main/java/org/postgresql/pljava/Adjusting.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2023 Tada AB and other contributors, as listed below.
* Copyright (c) 2019-2024 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand Down Expand Up @@ -147,16 +147,34 @@ private XML() { } // no instances
* {@link Exception#getSuppressed getSuppressed}. The return is
* immediate, without any remaining names being tried, if an exception
* is caught that is not assignable to a class in the
* <var>expected</var> list. Such an exception will be passed to the
* <var>onUnexpected</var> handler if that is non-null; otherwise,
* it will be returned (or added to the suppressed list of the
* exception to be returned) just as expected exceptions are.
* <var>expected</var> list. Such an exception is returned (or added to
* the suppressed list of an exception already to be returned) only if
* the <var>onUnexpected</var> handler is null; otherwise, it is passed
* to the handler and does not affect the method's return.
*<p>
* For some purposes, a single call of this method may not suffice: if
* alternate means to establish a desired configuration have existed and
* are not simply alternate property names that will accept the same
* value. For such a case, this method may be called more than once. The
* caller abandons the sequence of calls after the first call that
* returns null (indicating that it either succeeded, or incurred an
* unexpected exception and passed it to the <var>onUnexpected</var>
* handler. Otherwise, the exception returned by the first call can be
* passed as <var>caught</var> to the next call, instead of passing the
* usual null. (When a non-null <var>caught</var> is passed, it will be
* returned on failure, even if an unexpected exception has been caught;
* therefore, should it ever be necessary to chain more than two of
* these calls, the caller should abandon the sequence as soon as a call
* returns null <em>or</em> returns its <var>caught</var> argument with
* no growth of its suppressed list.)
* @param setter typically a method reference for a method that
* takes a string key and some value.
* @param value the value to pass to the setter
* @param expected a list of exception classes that can be foreseen
* to indicate that a key was not recognized, and the operation
* should be retried with the next possible key.
* @param caught null, or an exception returned by a preceding call if
* an operation cannot be implemented with one call of this method
* @param onUnexpected invoked, if non-null, on an {@code Exception}
* that is caught and matches nothing in the expected list, instead
* of returning it. If this parameter is null, such an exception is
Expand All @@ -165,16 +183,19 @@ private XML() { } // no instances
* immediate, without trying remaining names, if any.
* @param names one or more String keys to be tried in order until
* the action succeeds.
* @return null if any attempt succeeded, otherwise an exception,
* which may have further exceptions in its suppressed list.
* @return null if any attempt succeeded, or if the first exception
* caught was passed to the onUnexpected handler; otherwise the first
* exception caught (if the caller supplied a non-null
* <var>caught</var>, then that exception), which may have further
* exceptions in its suppressed list.
*/
public static <T, V extends T> Exception setFirstSupported(
SetMethod<? super T> setter, V value,
List<Class<? extends Exception>> expected,
Exception caught,
Consumer<? super Exception> onUnexpected, String... names)
{
requireNonNull(expected);
Exception caught = null;
for ( String name : names )
{
try
Expand Down Expand Up @@ -204,6 +225,18 @@ public static <T, V extends T> Exception setFirstSupported(
return caught;
}

/**
* Calls the six-argument overload passing null for <var>caught</var>.
*/
public static <T, V extends T> Exception setFirstSupported(
SetMethod<? super T> setter, V value,
List<Class<? extends Exception>> expected,
Consumer<? super Exception> onUnexpected, String... names)
{
return setFirstSupported(
setter, value, expected, null, onUnexpected, names);
}

/**
* A functional interface fitting various {@code setFeature} or
* {@code setProperty} methods in Java XML APIs.
Expand Down Expand Up @@ -268,6 +301,17 @@ public interface Parsing<T extends Parsing<T>>
/** Whether to allow a DTD at all. */
T allowDTD(boolean v);

/**
* Specifies that any DTD should be ignored (neither processed nor
* rejected as an error).
*<p>
* This treatment is available in Java 22 and later.
* In earlier Java versions, this will not succeed. Where it is
* supported, the most recent call of this method or of
* {@link #allowDTD allowDTD} will be honored.
*/
T ignoreDTD();

/**
* Whether to retrieve external "general" entities (those
* that can be used in the document body) declared in the DTD.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2023 Tada AB and other contributors, as listed below.
* Copyright (c) 2018-2024 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand Down Expand Up @@ -272,6 +272,44 @@
" WHERE extname = 'pljava'"
}
)

@SQLAction(implementor="postgresql_xml",
provides="xml_java_ge_22", requires="javaSpecificationGE", install=
"SELECT CASE WHEN" +
" javatest.javaSpecificationGE('22')" +
" THEN set_config('pljava.implementors', 'xml_java_ge_22,' || " +
" current_setting('pljava.implementors'), true) " +
"END"
)

@SQLAction(implementor="xml_java_ge_22", requires="lowLevelXMLEcho", install=
"WITH" +
" s(how) AS (SELECT unnest('{5,6,7}'::int[]))," +
" r(isdoc) AS (" +
" SELECT" +
" javatest.lowlevelxmlecho(" +
/*
* A truly minimal DTD, <!DOCTYPE a>, cannot be ignored by Java 22's SAX/DOM
* parser (though it can be, when using the StAX API). NullPointerException
* calling getActiveGrammar().isImmutable() is the result. Reported on
* bugreport.java.com but still awaiting assignment of a bug ID. Including
* either an externalID or an internal subset (like the empty [] here)
* avoids the issue.
*/
" '<!DOCTYPE a []><a/>'::xml, how, params) IS DOCUMENT" +
" FROM" +
" s," +
" (SELECT null::void AS ignoreDTD) AS params" +
" )" +
"SELECT" +
" CASE WHEN every(isdoc)" +
" THEN javatest.logmessage('INFO', 'jdk.xml.dtd.support=ignore OK')" +
" ELSE javatest.logmessage('WARNING', 'jdk.xml.dtd.support=ignore NG')" +
" END " +
"FROM" +
" r"
)

@MappedUDT(schema="javatest", name="onexml", structure="c1 xml",
implementor="postgresql_xml",
comment="A composite type mapped by the PassXML example class")
Expand Down Expand Up @@ -783,8 +821,7 @@ public static SQLXML lowLevelXMLEcho(
*<p>
* Column names in the <em>adjust</em> row are case-insensitive versions of
* the method names in {@link Adjusting.XML.Parsing}, and the value of each
* column should be of the appropriate type (at present, boolean for all of
* them).
* column should be of the appropriate type (if the method has a parameter).
* @param adjust A row type as described above, possibly of no columns if no
* adjustments are wanted
* @param axp An instance of Adjusting.XML.Parsing
Expand All @@ -804,6 +841,8 @@ T applyAdjustments(ResultSet adjust, T axp)
axp.lax(adjust.getBoolean(i));
else if ( "allowDTD".equalsIgnoreCase(k) )
axp.allowDTD(adjust.getBoolean(i));
else if ( "ignoreDTD".equalsIgnoreCase(k) )
axp.ignoreDTD();
else if ( "externalGeneralEntities".equalsIgnoreCase(k) )
axp.externalGeneralEntities(adjust.getBoolean(i));
else if ( "externalParameterEntities".equalsIgnoreCase(k) )
Expand Down
Loading
Loading