Every endpoint API created by the {@code Javassist}-based builders in this
+ * module extends this class so that a single {@link InvocationHandler} can be
+ * attached at construction time. The handler is later used to dispatch incoming
+ * calls to the appropriate backend implementation, effectively turning the
+ * generated subclass into a delegating proxy.
+ *
+ * This class is intentionally simple: it only stores the handler reference
+ * and exposes it through {@link #getHandler()}. Concrete subclasses are
+ * generated at runtime by
+ * {@link org.apache.cxf.endpoint.jaxrs.JaxrsEndpointApiCtClassBuilder},
+ * {@link org.apache.cxf.endpoint.jaxws.JaxwsEndpointApiCtClassBuilder} and
+ * their related interface / implementation variants.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see InvocationHandler
+ * @see org.apache.cxf.endpoint.jaxrs.JaxrsEndpointApiCtClassBuilder
+ * @see org.apache.cxf.endpoint.jaxws.JaxwsEndpointApiCtClassBuilder
+ */
public abstract class EndpointApi {
+ /**
+ * Handler invoked for every method call dispatched to the generated
+ * endpoint API. May be {@code null} for instances created with the
+ * default no-arg constructor; callers must tolerate that case.
+ */
private InvocationHandler handler;
-
+
+ /**
+ * No-argument constructor used by generated subclasses and the
+ * reflection-based instantiation paths in the builder helpers.
+ */
public EndpointApi() {
}
-
+
+ /**
+ * Stores the supplied {@link InvocationHandler} so it can later be
+ * retrieved through {@link #getHandler()}.
+ *
+ * @param handler dispatcher that should receive every method invocation,
+ * may be {@code null}.
+ */
public EndpointApi(InvocationHandler handler) {
this.handler = handler;
}
+ /**
+ * Returns the {@link InvocationHandler} that was passed to the
+ * constructor, or {@code null} when this instance was created via the
+ * default constructor.
+ *
+ * @return the stored handler, possibly {@code null}.
+ */
public InvocationHandler getHandler() {
return handler;
}
-
-
+
+
}
diff --git a/src/main/java/org/apache/cxf/endpoint/annotation/WebBound.java b/src/main/java/org/apache/cxf/endpoint/annotation/WebBound.java
index de1bfc6..6787496 100644
--- a/src/main/java/org/apache/cxf/endpoint/annotation/WebBound.java
+++ b/src/main/java/org/apache/cxf/endpoint/annotation/WebBound.java
@@ -26,10 +26,42 @@
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
+/**
+ * Marker annotation that binds arbitrary contextual data to a generated
+ * JAX-RS or JAX-WS endpoint API class or method.
+ *
+ * The {@link #uid()} attribute carries an opaque key (typically a primary
+ * identifier or a token) while {@link #json()} carries an arbitrary JSON
+ * payload that the runtime may surface to the implementation. Both
+ * attributes default to values that make the annotation effectively
+ * inert when no binding is required.
+ *
+ * The annotation may be placed on a class (to apply to every method of
+ * the generated endpoint) or on an individual method. It is
+ * {@link Inherited} so that subclasses of a generated endpoint inherit
+ * the binding declared on a parent type.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see org.apache.cxf.endpoint.jaxrs.definition.RestBound
+ * @see org.apache.cxf.endpoint.jaxws.definition.SoapBound
+ */
public @interface WebBound {
+ /**
+ * Opaque key (usually a primary identifier) used by the runtime to
+ * locate contextual data for the bound target.
+ *
+ * @return the configured uid, or an empty string when not set.
+ */
String uid() default "";
+ /**
+ * JSON payload attached to the bound target, serialised by the
+ * implementation to expose structured metadata.
+ *
+ * @return the configured JSON payload, or an empty object when not set.
+ */
String json() default "{}";
}
diff --git a/src/main/java/org/apache/cxf/endpoint/annotation/WebEndpoint.java b/src/main/java/org/apache/cxf/endpoint/annotation/WebEndpoint.java
index 4377979..cf02a1e 100644
--- a/src/main/java/org/apache/cxf/endpoint/annotation/WebEndpoint.java
+++ b/src/main/java/org/apache/cxf/endpoint/annotation/WebEndpoint.java
@@ -24,22 +24,81 @@
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
-@Documented
+@Documented
@Inherited
+/**
+ * Class-level annotation that captures the deployment address and
+ * interceptor / feature configuration for a generated web endpoint.
+ *
+ * The {@link #addr()} attribute is mandatory and supplies the URL at
+ * which the generated endpoint should be exposed. The remaining
+ * attributes accept arrays of fully qualified class names that will be
+ * instantiated by the runtime as in/out interceptors, fault handlers,
+ * features, and generic JAX-WS / CXF handlers. Each list defaults to
+ * an empty string so that no extras are wired in by default.
+ *
+ * This annotation is meant to be declared once per generated endpoint
+ * class and is {@link Inherited} so subclasses inherit the same
+ * configuration.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ */
public @interface WebEndpoint {
-
+
+ /**
+ * URL where the endpoint will be published.
+ *
+ * @return the deployment address; never {@code null}.
+ */
String addr();
-
+
+ /**
+ * Fully qualified class names of inbound interceptors to install.
+ *
+ * @return array of interceptor class names; defaults to a single
+ * empty entry.
+ */
String[] inInterceptors() default {""};
+ /**
+ * Fully qualified class names of outbound interceptors to install.
+ *
+ * @return array of interceptor class names; defaults to a single
+ * empty entry.
+ */
String[] outInterceptors() default {""};
-
+
+ /**
+ * Fully qualified class names of inbound fault handlers to install.
+ *
+ * @return array of fault-handler class names; defaults to a single
+ * empty entry.
+ */
String[] inFaults() default {""};
+ /**
+ * Fully qualified class names of outbound fault handlers to install.
+ *
+ * @return array of fault-handler class names; defaults to a single
+ * empty entry.
+ */
String[] outFaults() default {""};
-
+
+ /**
+ * Fully qualified class names of CXF features to enable.
+ *
+ * @return array of feature class names; defaults to a single empty
+ * entry.
+ */
String[] features() default {""};
-
+
+ /**
+ * Fully qualified class names of generic JAX-WS handlers to install.
+ *
+ * @return array of handler class names; defaults to a single empty
+ * entry.
+ */
String[] handlers() default {""};
-
+
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilder.java
index 4fa6a12..9afe8bc 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilder.java
@@ -27,154 +27,267 @@
import javassist.bytecode.ConstPool;
/**
- *
- * 动态构建rs接口
- * The builder wires the standard JAX-RS metadata ({@code @Path},
+ * {@code @Produces}, {@code @WebBound}) onto the generated class and
+ * exposes a fluent API to add annotated methods, fields, and
+ * constructors. Each {@code new*} / {@code add*} method mutates the
+ * underlying {@link CtClass} in-place and returns {@code this}, so
+ * calls can be chained. The final class can be obtained as a
+ * {@link CtClass} through {@link #build()}, as a {@link Class} through
+ * {@link #toClass()}, or as an already-instantiated proxy through
+ * {@link #toInstance(InvocationHandler)}.
+ *
+ * This is the JAX-RS counterpart of
+ * {@link org.apache.cxf.endpoint.jaxws.JaxwsEndpointApiCtClassBuilder}.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxrsEndpointApiUtils
+ * @see JaxrsEndpointApiInterfaceCtClassBuilder
+ * @see JaxrsEndpointApiImplCtClassBuilder
*/
public class JaxrsEndpointApiCtClassBuilder implements Builder {
- // 构建动态类
+ /**
+ * Class pool used to resolve types and define the generated
+ * endpoint class. Configured by the constructors.
+ */
protected ClassPool pool = null;
+ /**
+ * {@link CtClass} representing the generated endpoint. Mutated in
+ * place by every fluent setter on this builder.
+ */
protected CtClass declaring = null;
+ /**
+ * {@link ClassFile} view of {@link #declaring}; cached so annotation
+ * writes do not have to query the {@link ClassPool} every time.
+ */
protected ClassFile ccFile = null;
//private Loader loader = new Loader(pool);
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}
+ * provided by {@link ClassPoolFactory#getDefaultPool()}.
+ *
+ * @param classname fully qualified name of the class to generate.
+ * @throws CannotCompileException if the generated class cannot be
+ * compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxrsEndpointApiCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
-
+
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the class.
+ * @param classname fully qualified name of the class to generate.
+ * @throws CannotCompileException if the generated class cannot be
+ * compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxrsEndpointApiCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
this.pool = pool;
this.declaring = JaxrsEndpointApiUtils.makeClass(pool, classname);
-
- /* 获得 JaxwsHandler 类作为动态类的父类 */
+
+ /* Resolve EndpointApi as the generated class' parent. */
CtClass superclass = pool.get(EndpointApi.class.getName());
declaring.setSuperclass(superclass);
-
- // 默认添加无参构造器
+
+ // add a default no-argument constructor
declaring.addConstructor(CtNewConstructor.defaultConstructor(declaring));
-
+
this.ccFile = this.declaring.getClassFile();
-
+
}
-
- /**
- * 添加类注解 @Path
- * @param path : Defines a URI template for the resource class or method, must not include matrix parameters.
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @Path} annotation to the generated class.
+ *
+ * @param path URI template that defines the resource base path; must
+ * not contain matrix parameters.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder path(final String path) {
ConstPool constPool = this.ccFile.getConstPool();
JavassistUtils.addClassAnnotation(declaring, JaxrsEndpointApiUtils.annotPath(constPool, path));
-
+
return this;
}
-
- /**
- * 添加类注解 @Produces
- * @param mediaTypes the media types
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @Produces} annotation to the generated class.
+ * When no media types are supplied the default {@code */*}
+ * value is used.
+ *
+ * @param mediaTypes produced media types.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder produces(final String... mediaTypes) {
String[] noyNullMediaTypes = ArrayUtils.isNotEmpty(mediaTypes) ? mediaTypes : new String[] { "*/*" };
ConstPool constPool = this.ccFile.getConstPool();
JavassistUtils.addClassAnnotation(declaring, JaxrsEndpointApiUtils.annotProduces(constPool, noyNullMediaTypes));
-
+
return this;
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param uid : The value of uid
- * @param json : The value of json
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation with the supplied primary
+ * key and JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that backs the bound target.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder bind(final String uid, final String json) {
return bind(new RestBound(uid, json));
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link RestBound} instance
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation derived from the supplied
+ * descriptor.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder bind(final RestBound bound) {
ConstPool constPool = this.ccFile.getConstPool();
JavassistUtils.addClassAnnotation(declaring, JaxrsEndpointApiUtils.annotWebBound(constPool, bound));
-
+
return this;
}
-
+
/**
- * Compiles the given source code and creates a field.
- * Examples of the source code are:
- *
- *
- * "public String name;"
- * "public int k = 3;"
+ * Compiles the given source code and adds a new field to the
+ * generated class. The source must include the trailing
+ * semicolon — see {@link CtField#make(String, CtClass)}.
*
- * Note that the source code ends with ';'
- * (semicolon).
- *
- * @param src the source text.
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
+ * @param src the source text, e.g. {@code "public int k = 3;"}.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * provided snippet.
*/
public JaxrsEndpointApiCtClassBuilder makeField(final String src) throws CannotCompileException {
//创建属性
declaring.addField(CtField.make(src, declaring));
return this;
}
-
+
+ /**
+ * Adds a strongly typed field initialised with the supplied value
+ * via the {@link CtFieldBuilder} helper.
+ *
+ * @param fieldClass runtime type of the new field.
+ * @param fieldName simple name of the new field.
+ * @param fieldValue initial value expressed as a Java expression
+ * evaluated inside the generated class.
+ * @param type of the new field.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the initialiser cannot be
+ * compiled.
+ * @throws NotFoundException if the field type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newField(final Class fieldClass, final String fieldName, final String fieldValue) throws CannotCompileException, NotFoundException {
CtFieldBuilder.create(declaring, this.pool.get(fieldClass.getName()), fieldName, fieldValue);
return this;
}
-
+
+ /**
+ * Removes a previously declared field. If the field does not exist
+ * the call is a no-op.
+ *
+ * @param fieldName simple name of the field to remove.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the field lookup fails unexpectedly.
+ */
public JaxrsEndpointApiCtClassBuilder removeField(final String fieldName) throws NotFoundException {
-
+
// 检查字段是否已经定义
if(!JavassistUtils.hasField(declaring, fieldName)) {
return this;
}
-
+
declaring.removeField(declaring.getDeclaredField(fieldName));
-
+
return this;
}
-
+
+ /**
+ * Convenience overload that wraps the supplied arguments in a
+ * {@link RestMethod} and forwards to
+ * {@link #newMethod(Class, RestMethod, RestBound, RestParam[])}.
+ *
+ * @param rtClass return type of the generated method, may be
+ * {@code null} for {@code void}.
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param bound method-level binding or {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, final HttpMethodEnum method, final String name,final String path, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(rtClass , new RestMethod(method, name, path), bound, params);
}
-
+
+ /**
+ * Convenience overload without a method-level binding.
+ *
+ * @param rtClass return type of the generated method, may be
+ * {@code null} for {@code void}.
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, final HttpMethodEnum method, final String name,final String path, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(rtClass , new RestMethod(method, name, path), params);
}
-
- /**
- *
- * 根据参数构造一个新的方法
- * @param rtClass :返回对象类型
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Adds a fully-described REST method (verb, path, binding, and
+ * parameters) to the generated class. The generated body
+ * dispatches every invocation through the configured
+ * {@link InvocationHandler}.
+ *
+ * @param rtClass return type of the generated method, may be
+ * {@code null} for {@code void}.
+ * @param method descriptor carrying the verb, name and path.
+ * @param bound method-level binding, may be {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, final RestMethod method, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
-
+
ConstPool constPool = this.ccFile.getConstPool();
-
+
// 创建抽象方法
CtClass returnType = rtClass != null ? pool.get(rtClass.getName()) : CtClass.voidType;
CtMethod ctMethod = null;
@@ -183,8 +296,8 @@ public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, fina
// 有参方法
if(parameters != null && parameters.length > 0) {
ctMethod = new CtMethod(returnType, method.getName(), parameters, declaring);
- }
- // 无参方法
+ }
+ // 无参方法
else {
ctMethod = new CtMethod(returnType, method.getName() , null, declaring);
}
@@ -194,75 +307,168 @@ public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, fina
JaxrsEndpointApiUtils.methodCatch(pool, ctMethod);
// 为方法添加 @HttpMethod、 @GET、 @POST、 @PUT、 @DELETE、 @PATCH、 @HEAD、 @OPTIONS、@Path、、@Consumes、@Produces、@RestBound、@RestParam 注解
JaxrsEndpointApiUtils.methodAnnotations(ctMethod, constPool, method, bound, params);
-
+
//新增方法
declaring.addMethod(ctMethod);
-
+
return this;
}
-
+
+ /**
+ * Convenience overload without a method-level binding.
+ *
+ * @param rtClass return type of the generated method.
+ * @param method descriptor carrying the verb, name and path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, final RestMethod method, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(rtClass, method, null, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type and the
+ * method-level binding.
+ *
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final HttpMethodEnum method, final String name, final String path, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null , new RestMethod(method, name, path), null, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type but keeps the
+ * method-level binding.
+ *
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final HttpMethodEnum method, final String name, final String path, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null , new RestMethod(method, name, path), bound, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type.
+ *
+ * @param method descriptor carrying the verb, name and path.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final RestMethod method, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null, method, bound, params);
}
-
+
+ /**
+ * Convenience overload that omits both the return type and the
+ * method-level binding.
+ *
+ * @param method descriptor carrying the verb, name and path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiCtClassBuilder newMethod(final RestMethod method, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null, method, null, params);
}
-
+
+ /**
+ * Removes a previously declared method. If the method does not
+ * exist the call is a no-op.
+ *
+ * @param methodName simple name of the method to remove.
+ * @param params parameter descriptors used to disambiguate
+ * overloaded methods; may be empty for non
+ * overloaded methods.
+ * @param unused generic parameter kept for symmetry with
+ * the other {@code newMethod} overloads.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the method lookup fails
+ * unexpectedly.
+ */
public JaxrsEndpointApiCtClassBuilder removeMethod(final String methodName, RestParam>... params) throws NotFoundException {
-
+
// 有参方法
if(params != null && params.length > 0) {
-
+
// 方法参数
CtClass[] parameters = JaxrsEndpointApiUtils.makeParams(pool, params);
-
+
// 检查方法是否已经定义
if(!JavassistUtils.hasMethod(declaring, methodName, parameters)) {
return this;
}
-
+
declaring.removeMethod(declaring.getDeclaredMethod(methodName, parameters));
-
+
}
else {
-
+
// 检查方法是否已经定义
if(!JavassistUtils.hasMethod(declaring, methodName)) {
return this;
}
-
+
declaring.removeMethod(declaring.getDeclaredMethod(methodName));
-
+
}
-
+
return this;
}
-
+
+ /**
+ * Returns the underlying {@link CtClass} so the caller can perform
+ * additional Javassist-level manipulations or feed it to
+ * {@link #toClass()} / {@link #toInstance(InvocationHandler)}.
+ *
+ * @return the live {@link CtClass} handled by this builder.
+ */
@Override
public CtClass build() {
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Resolves the generated class through the current class loader and
+ * detaches the {@link CtClass} from the pool so the in-memory cache
+ * does not grow unbounded.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
// 通过类加载器加载该CtClass
@@ -270,9 +476,33 @@ public Class> toClass() throws CannotCompileException {
} finally {
// 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
-
+
+ /**
+ * Adds an {@link InvocationHandler}-accepting constructor, loads the
+ * generated class, instantiates it through the new constructor and
+ * detaches the {@link CtClass}.
+ *
+ * @param handler handler that will receive every dispatched
+ * invocation.
+ * @return the freshly instantiated proxy.
+ * @throws CannotCompileException if the constructor body cannot
+ * be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws InstantiationException if the generated class cannot
+ * be instantiated.
+ * @throws IllegalAccessException if the constructor is not
+ * accessible.
+ * @throws IllegalArgumentException if the supplied arguments do
+ * not match the constructor.
+ * @throws InvocationTargetException if the constructor throws.
+ * @throws NoSuchMethodException if the generated constructor
+ * is missing.
+ * @throws SecurityException if a security manager refuses
+ * reflective access.
+ */
public Object toInstance(final InvocationHandler handler) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
try {
// 设置InvocationHandler参数构造器
@@ -282,7 +512,7 @@ public Object toInstance(final InvocationHandler handler) throws CannotCompileEx
} finally {
// 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilder.java
index 1cae177..482a34d 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilder.java
@@ -18,90 +18,138 @@
import javassist.NotFoundException;
/**
- *
- * 动态构建ws接口
- * http://www.cnblogs.com/sunfie/p/5154246.html
- * http://blog.csdn.net/youaremoon/article/details/50766972
- * https://my.oschina.net/GameKing/blog/794580
- * http://wsmajunfeng.iteye.com/blog/1912983
+ * Builder that produces a paired JAX-RS interface and implementation
+ * class on top of {@link JaxrsEndpointApiCtClassBuilder}.
+ *
+ * The implementation class is generated under the {@code $Impl}
+ * suffix ({@link #IMPL_CLASSNAME_PREFIX}) and implements the
+ * interface produced by the inner
+ * {@link JaxrsEndpointApiInterfaceCtClassBuilder}. Class-level
+ * configuration ({@code @Path}, {@code @Produces},
+ * {@code @WebBound}) is forwarded to the interface builder so that
+ * callers can treat the pair as a single fluent surface.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxrsEndpointApiCtClassBuilder
+ * @see JaxrsEndpointApiInterfaceCtClassBuilder
*/
public class JaxrsEndpointApiImplCtClassBuilder extends JaxrsEndpointApiCtClassBuilder implements Builder {
- /**
- * 生成的实现类名前缀
- */
- private static final String IMPL_CLASSNAME_PREFIX = "$Impl";
+ /**
+ * Suffix appended to the supplied class name to derive the
+ * implementation class name.
+ */
+ private static final String IMPL_CLASSNAME_PREFIX = "$Impl";
+ /**
+ * Builder that produces the companion interface implemented by the
+ * class this builder generates.
+ */
private JaxrsEndpointApiInterfaceCtClassBuilder classBuilder;
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}.
+ *
+ * @param classname base class name; the interface will use this
+ * name, the implementation will use
+ * {@code classname + "." + IMPL_CLASSNAME_PREFIX}.
+ * @throws CannotCompileException if the implementation class
+ * cannot be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiImplCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
-
+
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the
+ * classes.
+ * @param classname base class name.
+ * @throws CannotCompileException if the implementation class
+ * cannot be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiImplCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
super(pool, classname + "." + IMPL_CLASSNAME_PREFIX);
-
+
this.classBuilder = new JaxrsEndpointApiInterfaceCtClassBuilder(pool, classname);
-
+
}
-
- /**
- * 添加类注解 @Path
- * @param path : Defines a URI template for the resource class or method, must not include matrix parameters.
- * @return {@link JaxrsEndpointApiImplCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the call to the interface builder so both generated
+ * artifacts receive the {@code @Path} annotation.
+ *
+ * @param path URI template for the resource.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiImplCtClassBuilder path(final String path) {
this.classBuilder.path(path);
return this;
}
-
- /**
- * 添加类注解 @Produces
- * @param mediaTypes the media types
- * @return {@link JaxrsEndpointApiImplCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the call to the interface builder so both generated
+ * artifacts receive the {@code @Produces} annotation.
+ *
+ * @param mediaTypes produced media types.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiImplCtClassBuilder produces(final String... mediaTypes) {
this.classBuilder.produces(mediaTypes);
return this;
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param uid : The value of uid
- * @param json : The value of json
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation with the supplied
+ * primary key and JSON payload by forwarding to
+ * {@link #bind(RestBound)}.
+ *
+ * @param uid primary key.
+ * @param json JSON payload.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder bind(final String uid, final String json) {
return bind(new RestBound(uid, json));
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link RestBound} instance
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation by forwarding the
+ * descriptor to the interface builder.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiCtClassBuilder bind(final RestBound bound) {
this.classBuilder.bind(bound);
return this;
}
-
- /**
- *
- * 根据参数构造一个新的方法
- * @param rtClass :返回对象类型
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxrsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Generates an abstract method on the companion interface and the
+ * matching concrete method on the implementation class.
+ *
+ * @param rtClass return type of the generated method.
+ * @param method descriptor carrying the verb, name and path.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
@Override
public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, final RestMethod method, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
-
+
this.classBuilder.abstractMethod(rtClass, method, bound, params);
-
+
// 创建抽象方法
CtClass returnType = rtClass != null ? pool.get(rtClass.getName()) : CtClass.voidType;
CtMethod ctMethod = null;
@@ -110,8 +158,8 @@ public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, fina
// 有参方法
if(parameters != null && parameters.length > 0) {
ctMethod = new CtMethod(returnType, method.getName(), parameters, declaring);
- }
- // 无参方法
+ }
+ // 无参方法
else {
ctMethod = new CtMethod(returnType, method.getName() , null, declaring);
}
@@ -119,13 +167,19 @@ public JaxrsEndpointApiCtClassBuilder newMethod(final Class rtClass, fina
JaxrsEndpointApiUtils.methodBody(ctMethod, method);
// 设置方法异常捕获逻辑
JaxrsEndpointApiUtils.methodCatch(pool, ctMethod);
-
+
//新增方法
declaring.addMethod(ctMethod);
-
+
return this;
}
-
+
+ /**
+ * Hooks the generated implementation class to the companion
+ * interface and returns the resulting {@link CtClass}.
+ *
+ * @return the implementation class.
+ */
@Override
public CtClass build() {
try {
@@ -136,14 +190,15 @@ public CtClass build() {
}
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Loads the generated class (with the companion interface as its
+ * superclass) and detaches the {@link CtClass} from the pool.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
// 设置接口
@@ -153,9 +208,33 @@ public Class> toClass() throws CannotCompileException {
} finally {
// 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
-
+
+ /**
+ * Adds the {@link InvocationHandler}-accepting constructor, hooks
+ * the implementation class to its interface, and instantiates the
+ * proxy.
+ *
+ * @param handler handler that will receive every dispatched
+ * invocation.
+ * @return the freshly instantiated proxy.
+ * @throws CannotCompileException if the constructor body cannot
+ * be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws InstantiationException if the generated class cannot
+ * be instantiated.
+ * @throws IllegalAccessException if the constructor is not
+ * accessible.
+ * @throws IllegalArgumentException if the supplied arguments do
+ * not match the constructor.
+ * @throws InvocationTargetException if the constructor throws.
+ * @throws NoSuchMethodException if the generated constructor
+ * is missing.
+ * @throws SecurityException if a security manager refuses
+ * reflective access.
+ */
public Object toInstance(final InvocationHandler handler) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
try {
// 设置接口
@@ -167,7 +246,7 @@ public Object toInstance(final InvocationHandler handler) throws CannotCompileEx
} finally {
// 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilder.java
index 449fd7b..bd31832 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilder.java
@@ -23,44 +23,87 @@
import javassist.bytecode.ConstPool;
/**
- *
- * 动态构建ws接口
- * http://www.cnblogs.com/sunfie/p/5154246.html
- * http://blog.csdn.net/youaremoon/article/details/50766972
- * https://blog.csdn.net/tscyds/article/details/78415172
- * https://my.oschina.net/GameKing/blog/794580
- * http://wsmajunfeng.iteye.com/blog/1912983
+ * Builder that creates a JAX-RS resource interface as a Javassist
+ * {@link CtClass}.
+ *
+ * The generated interface extends {@link Cloneable} and exposes
+ * abstract methods annotated with the standard JAX-RS annotations
+ * ({@code @GET}, {@code @POST}, {@code @Path}, {@code @QueryParam},
+ * etc.). This builder is typically used together with
+ * {@link JaxrsEndpointApiImplCtClassBuilder} which generates the
+ * paired implementation class.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxrsEndpointApiCtClassBuilder
+ * @see JaxrsEndpointApiImplCtClassBuilder
*/
public class JaxrsEndpointApiInterfaceCtClassBuilder implements Builder {
-
- // 构建动态类
+
+ /**
+ * Class pool used to resolve types and define the generated
+ * interface. Configured by the constructors.
+ */
private ClassPool pool = null;
+ /**
+ * {@link CtClass} representing the generated interface. Mutated in
+ * place by every fluent setter on this builder.
+ */
private CtClass declaring = null;
+ /**
+ * {@link ClassFile} view of {@link #declaring}; cached so
+ * annotation writes do not have to query the {@link ClassPool}
+ * every time.
+ */
private ClassFile ccFile = null;
-
+
//private Loader loader = new Loader(pool);
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}
+ * provided by {@link ClassPoolFactory#getDefaultPool()}.
+ *
+ * @param classname fully qualified name of the interface to
+ * generate.
+ * @throws CannotCompileException if the generated interface cannot
+ * be compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the
+ * interface.
+ * @param classname fully qualified name of the interface to
+ * generate.
+ * @throws CannotCompileException if the generated interface cannot
+ * be compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
this.pool = pool;
this.declaring = JaxrsEndpointApiUtils.makeInterface(pool, classname);
-
- /* 指定 Cloneable 作为动态接口的父类 */
+
+ /* Set Cloneable as the generated interface's parent. */
CtClass superclass = pool.get(Cloneable.class.getName());
declaring.setSuperclass(superclass);
-
+
this.ccFile = this.declaring.getClassFile();
}
-
- /**
- * 添加类注解 @Path
- * @param path : Defines a URI template for the resource class or method, must not include matrix parameters.
- * @return {@link JaxrsEndpointApiInterfaceCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @Path} annotation to the generated interface.
+ *
+ * @param path URI template that defines the resource base path.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder path(final String path) {
ConstPool constPool = this.ccFile.getConstPool();
@@ -69,11 +112,14 @@ public JaxrsEndpointApiInterfaceCtClassBuilder path(final String path) {
return this;
}
- /**
- * 添加类注解 @Produces
- * @param mediaTypes the media types
- * @return {@link JaxrsEndpointApiInterfaceCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @Produces} annotation to the generated
+ * interface. When no media types are supplied the default
+ * {@code */*} value is used.
+ *
+ * @param mediaTypes produced media types.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder produces(final String... mediaTypes) {
String[] noyNullMediaTypes = ArrayUtils.isNotEmpty(mediaTypes) ? mediaTypes : new String[] { "*/*" };
@@ -83,21 +129,25 @@ public JaxrsEndpointApiInterfaceCtClassBuilder produces(final String... mediaTyp
return this;
}
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param uid : The value of uid
- * @param json : The value of json
- * @return {@link JaxrsEndpointApiInterfaceCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @WebBound} annotation with the supplied primary
+ * key and JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that backs the bound target.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder bind(final String uid, final String json) {
return bind(new RestBound(uid, json));
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link RestBound} instance
- * @return {@link JaxrsEndpointApiInterfaceCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation derived from the supplied
+ * descriptor.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder bind(final RestBound bound) {
ConstPool constPool = this.ccFile.getConstPool();
@@ -127,6 +177,19 @@ public JaxrsEndpointApiInterfaceCtClassBuilder makeField(final String src) throw
return this;
}
+ /**
+ * Adds a strongly typed field to the generated interface. If the
+ * field already exists, the call is a no-op.
+ *
+ * @param fieldClass runtime type of the new field.
+ * @param fieldName simple name of the new field.
+ * @param fieldValue initial value expressed as a string literal.
+ * @param type of the new field.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the field cannot be compiled.
+ * @throws NotFoundException if the field type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder newField(final Class fieldClass, final String fieldName, final String fieldValue) throws CannotCompileException, NotFoundException {
// 检查字段是否已经定义
@@ -144,6 +207,14 @@ public JaxrsEndpointApiInterfaceCtClassBuilder newField(final Class field
return this;
}
+ /**
+ * Removes a previously declared field. If the field does not exist
+ * the call is a no-op.
+ *
+ * @param fieldName simple name of the field to remove.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the field lookup fails unexpectedly.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder removeField(final String fieldName) throws NotFoundException {
// 检查字段是否已经定义
@@ -156,26 +227,65 @@ public JaxrsEndpointApiInterfaceCtClassBuilder removeField(final String fiel
return this;
}
+ /**
+ * Convenience overload that wraps the supplied arguments in a
+ * {@link RestMethod} and forwards to
+ * {@link #abstractMethod(Class, RestMethod, RestBound, RestParam[])}.
+ *
+ * @param rtClass return type of the generated method, may be
+ * {@code null} for {@code void}.
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param bound method-level binding or {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final Class rtClass, final HttpMethodEnum method, final String name,final String path, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(rtClass , new RestMethod(method, name, path), bound, params);
}
-
+
+ /**
+ * Convenience overload without a method-level binding.
+ *
+ * @param rtClass return type of the generated method.
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final Class rtClass, final HttpMethodEnum method, final String name,final String path, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(rtClass , new RestMethod(method, name, path), params);
}
-
- /**
- *
- * 根据参数构造一个新的方法
- * @param rtClass :对象类型
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxrsEndpointApiInterfaceCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Adds a fully-described abstract REST method (verb, path, binding,
+ * and parameters) to the generated interface. The method will be
+ * annotated with the appropriate JAX-RS annotations.
+ *
+ * @param rtClass return type of the generated method, may be
+ * {@code null} for {@code void}.
+ * @param method descriptor carrying the verb, name and path.
+ * @param bound method-level binding, may be {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final Class rtClass, final RestMethod method, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
ConstPool constPool = this.ccFile.getConstPool();
@@ -204,26 +314,103 @@ public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final Class
return this;
}
+ /**
+ * Convenience overload without a method-level binding.
+ *
+ * @param rtClass return type of the generated method.
+ * @param method descriptor carrying the verb, name and path.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final Class rtClass, final RestMethod method, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(rtClass, method, null, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type and the
+ * method-level binding.
+ *
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final HttpMethodEnum method, final String name,final String path, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null , new RestMethod(method, name, path), null, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type but keeps the
+ * method-level binding.
+ *
+ * @param method HTTP verb.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final HttpMethodEnum method, final String name, final String path, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null, new RestMethod(method, name, path), bound, params);
}
-
+
+ /**
+ * Convenience overload that omits the return type.
+ *
+ * @param method descriptor carrying the verb, name and path.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final RestMethod method, final RestBound bound, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null, method, bound, params);
}
-
+
+ /**
+ * Convenience overload that omits both the return type and the
+ * method-level binding.
+ *
+ * @param method descriptor carrying the verb, name and path.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder abstractMethod(final RestMethod method, RestParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null, method, null, params);
}
-
+
+ /**
+ * Removes a previously declared method. If the method does not
+ * exist the call is a no-op.
+ *
+ * @param methodName simple name of the method to remove.
+ * @param params parameter descriptors used to disambiguate
+ * overloaded methods; may be empty.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the method lookup fails
+ * unexpectedly.
+ */
public JaxrsEndpointApiInterfaceCtClassBuilder removeMethod(final String methodName, RestParam>... params) throws NotFoundException {
// 有参方法
@@ -254,26 +441,33 @@ public JaxrsEndpointApiInterfaceCtClassBuilder removeMethod(final String methodN
return this;
}
+ /**
+ * Returns the underlying {@link CtClass} so the caller can perform
+ * additional Javassist-level manipulations or feed it to
+ * {@link #toClass()}.
+ *
+ * @return the live {@link CtClass} handled by this builder.
+ */
@Override
public CtClass build() {
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Resolves the generated interface through the current class loader
+ * and detaches the {@link CtClass} from the pool so the in-memory
+ * cache does not grow unbounded.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
- // 通过类加载器加载该CtClass
return declaring.toClass();
} finally {
- // 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnum.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnum.java
index 2c9ef01..6c7de34 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnum.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnum.java
@@ -5,8 +5,21 @@
import java.util.NoSuchElementException;
+/**
+ * Enumeration of the standard JAX-RS / HTTP verbs that may be declared on a
+ * generated REST endpoint method.
+ *
+ * Each constant carries the canonical name (matching the constant in
+ * {@link jakarta.ws.rs.HttpMethod}) so that case-insensitive lookup is
+ * possible when parsing incoming requests. Use {@link #valueOfIgnoreCase(String)}
+ * to resolve a key regardless of casing.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.ws.rs.HttpMethod
+ */
public enum HttpMethodEnum {
-
+
/**
* HTTP GET method.
*/
@@ -35,17 +48,36 @@ public enum HttpMethodEnum {
* HTTP OPTIONS method.
*/
OPTIONS(HttpMethod.OPTIONS);
-
+
+ /**
+ * Canonical verb string (e.g. {@code "GET"}) carried by this enum
+ * constant.
+ */
private String key;
private HttpMethodEnum(String key) {
this.key = key;
}
+ /**
+ * Returns the canonical HTTP verb that backs this enum constant.
+ *
+ * @return the canonical verb, never {@code null}.
+ */
public String getKey() {
return key;
}
-
+
+ /**
+ * Resolves an enum constant by its canonical verb string, ignoring
+ * case.
+ *
+ * @param key the verb to resolve; matched case-insensitively against
+ * {@link #getKey()}.
+ * @return the matching {@link HttpMethodEnum} constant.
+ * @throws NoSuchElementException if no constant carries the supplied
+ * verb.
+ */
public static HttpMethodEnum valueOfIgnoreCase(String key) {
for (HttpMethodEnum apiType : HttpMethodEnum.values()) {
if(apiType.getKey().equalsIgnoreCase(key)) {
@@ -54,5 +86,5 @@ public static HttpMethodEnum valueOfIgnoreCase(String key) {
}
throw new NoSuchElementException("Cannot found ApiType with key '" + key + "'.");
}
-
+
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnum.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnum.java
index 594b48e..a5ee98e 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnum.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnum.java
@@ -4,8 +4,17 @@
import jakarta.ws.rs.Encoded;
/**
- * 参数注解类型枚举
- *
+ * Enumeration of the JAX-RS parameter-injection strategies supported by
+ * the generated REST endpoint builder.
+ *
+ * Each constant maps to one of the standard {@code jakarta.ws.rs}
+ * parameter annotations and is used by the code-generation helpers to
+ * decide which annotation to attach to a generated method parameter.
+ * Use {@link RestParam#setFrom(HttpParamEnum)} to switch the binding
+ * source for a particular parameter.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
* @see jakarta.ws.rs.BeanParam
* @see jakarta.ws.rs.CookieParam
* @see jakarta.ws.rs.HeaderParam
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestBound.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestBound.java
index eabc10a..a27b1b4 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestBound.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestBound.java
@@ -16,41 +16,88 @@
package org.apache.cxf.endpoint.jaxrs.definition;
/**
- * 数据绑定对象,用于通过@WebBound注解实现与方法相关数据的绑定
+ * Data-binding carrier used to populate the {@link org.apache.cxf.endpoint.annotation.WebBound}
+ * annotation on a generated JAX-RS endpoint method.
+ *
+ * {@link RestBound} keeps a primary key ({@link #getUid()}) and an
+ * optional JSON payload ({@link #getJson()}) that the generated
+ * endpoint makes available to the implementation through the
+ * annotation values. Instances are immutable in their key but expose
+ * setters so that callers can adjust the JSON payload without
+ * rebuilding the bound object.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see org.apache.cxf.endpoint.annotation.WebBound
+ * @see org.apache.cxf.endpoint.utils.JaxrsEndpointApiUtils#annotWebBound(javassist.bytecode.ConstPool, RestBound)
*/
public class RestBound {
-
+
+ /**
+ * Builds a bound with the supplied uid and an empty JSON payload.
+ *
+ * @param uid primary key for the bound target; never {@code null}.
+ */
public RestBound(String uid) {
this.uid = uid;
}
-
+
+ /**
+ * Builds a bound with both a primary key and a JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that describes the bound data.
+ */
public RestBound(String uid, String json) {
this.uid = uid;
this.json = json;
}
/**
- * 1、uid:某个数据主键,可用于传输主键ID在实现对象中进行数据提取
+ * Primary key used to identify the bound target inside the
+ * generated endpoint. Defaults to an empty string.
*/
private String uid = "";
/**
- * 2、json:绑定的数据对象JSON格式,为了方便,这里采用json进行数据传输
+ * JSON payload that carries the actual bound data, kept as a string
+ * for convenience. Defaults to an empty string.
*/
private String json = "";
+ /**
+ * Returns the configured primary key.
+ *
+ * @return the uid, never {@code null}.
+ */
public String getUid() {
return uid;
}
+ /**
+ * Overrides the primary key.
+ *
+ * @param uid new uid; must not be {@code null}.
+ */
public void setUid(String uid) {
this.uid = uid;
}
+ /**
+ * Returns the JSON payload that backs this bound.
+ *
+ * @return the JSON payload, possibly empty.
+ */
public String getJson() {
return json;
}
+ /**
+ * Overrides the JSON payload.
+ *
+ * @param json new JSON payload; may be {@code null} to clear the
+ * payload.
+ */
public void setJson(String json) {
this.json = json;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethod.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethod.java
index f58b813..cba03ae 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethod.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethod.java
@@ -23,6 +23,24 @@
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
+/**
+ * Descriptor for a single REST endpoint method generated by the
+ * {@link org.apache.cxf.endpoint.jaxrs.JaxrsEndpointApiCtClassBuilder}
+ * family of builders.
+ *
+ * The descriptor bundles the {@linkplain #getMethod() HTTP verb},
+ * {@linkplain #getName() Java method name} and {@linkplain #getPath()
+ * JAX-RS URI template} that should be attached to the generated
+ * method, along with optional {@code @Consumes} and {@code @Produces}
+ * media-type lists.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see HttpMethodEnum
+ * @see jakarta.ws.rs.Path
+ * @see jakarta.ws.rs.Consumes
+ * @see jakarta.ws.rs.Produces
+ */
public class RestMethod {
/**
@@ -72,12 +90,30 @@ public class RestMethod {
*/
private String[] consumes;
+ /**
+ * Builds a descriptor without {@code @Consumes} media types. The
+ * generated method will still receive the default {@code @Produces}
+ * value ({@code */*}).
+ *
+ * @param method HTTP verb for this method.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ */
public RestMethod(HttpMethodEnum method, String name, String path) {
this.method = method;
this.name = name;
this.path = path;
}
+ /**
+ * Builds a descriptor that also declares the supplied
+ * {@code @Consumes} media types.
+ *
+ * @param method HTTP verb for this method.
+ * @param name Java method name.
+ * @param path URI template appended to the resource path.
+ * @param consumes media types accepted by this method.
+ */
public RestMethod(HttpMethodEnum method, String name, String path, String... consumes) {
this.method = method;
this.name = name;
@@ -85,30 +121,68 @@ public RestMethod(HttpMethodEnum method, String name, String path, String... con
this.consumes = consumes;
}
+ /**
+ * Returns the {@code @Consumes} media types declared by this
+ * descriptor.
+ *
+ * @return the consumed media types, possibly {@code null}.
+ */
public String[] getConsumes() {
return consumes;
}
-
+
+ /**
+ * Returns the {@code @Produces} media types declared by this
+ * descriptor. Defaults to a single {@code */*} entry.
+ *
+ * @return the produced media types, never {@code null}.
+ */
public String[] getMediaTypes() {
return mediaTypes;
}
+ /**
+ * Replaces the {@code @Produces} media types.
+ *
+ * @param mediaTypes new produced media types.
+ */
public void setMediaTypes(String[] mediaTypes) {
this.mediaTypes = mediaTypes;
}
+ /**
+ * Replaces the {@code @Consumes} media types.
+ *
+ * @param consumes new consumed media types.
+ */
public void setConsumes(String[] consumes) {
this.consumes = consumes;
}
+ /**
+ * Returns the Java method name.
+ *
+ * @return the method name.
+ */
public String getName() {
return name;
}
+ /**
+ * Returns the HTTP verb.
+ *
+ * @return the verb, never {@code null}.
+ */
public HttpMethodEnum getMethod() {
return method;
}
+ /**
+ * Returns the URI template that follows the class-level
+ * {@code @Path}.
+ *
+ * @return the URI template.
+ */
public String getPath() {
return path;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestParam.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestParam.java
index b1ccabf..c0001ef 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestParam.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestParam.java
@@ -16,16 +16,35 @@
package org.apache.cxf.endpoint.jaxrs.definition;
/**
+ * Descriptor for a single JAX-RS endpoint method parameter that the
+ * generated builder will translate into a typed
+ * {@code @QueryParam}, {@code @PathParam}, {@code @HeaderParam}, ...
+ * annotation pair.
+ *
+ * The descriptor carries the {@linkplain #getType() parameter type},
+ * {@linkplain #getName() parameter name},
+ * {@linkplain #getFrom() binding source} and an optional
+ * {@linkplain #getDef() default value}. Use the various constructors
+ * to pick the subset of attributes the application needs to override
+ * while leaving the rest at their default values.
+ *
+ * @param the runtime type of the parameter.
+ * @author Loong Wan
+ * @since 3.0.0
+ * @see HttpParamEnum
+ * @see jakarta.ws.rs.DefaultValue
*/
public class RestParam {
/**
- * 参数对象类型
+ * Runtime type of the parameter; mandatory.
*/
private Class type;
-
+
/**
- * name :参数的名称
+ * Logical name of the parameter, surfaced as the value of the
+ * generated JAX-RS parameter annotation (e.g. {@code @QueryParam("id")}).
+ *
* @see jakarta.ws.rs.BeanParam
* @see jakarta.ws.rs.PathParam
* @see jakarta.ws.rs.QueryParam
@@ -35,9 +54,11 @@ public class RestParam {
* @see jakarta.ws.rs.HeaderParam
*/
private String name;
-
+
/**
- * from :参数来源
+ * Source the parameter should be bound to. Defaults to
+ * {@link HttpParamEnum#QUERY}.
+ *
* @see jakarta.ws.rs.BeanParam
* @see jakarta.ws.rs.PathParam
* @see jakarta.ws.rs.QueryParam
@@ -47,72 +68,145 @@ public class RestParam {
* @see jakarta.ws.rs.HeaderParam
*/
private HttpParamEnum from = HttpParamEnum.QUERY;
-
+
/**
- * Defines the default value of request meta-data that is bound using one of the
- * following annotations:
- * {@link jakarta.ws.rs.PathParam},
- * {@link jakarta.ws.rs.QueryParam},
- * {@link jakarta.ws.rs.MatrixParam},
- * {@link jakarta.ws.rs.CookieParam},
- * {@link jakarta.ws.rs.FormParam}, or
- * {@link jakarta.ws.rs.HeaderParam}.
- * The default value is used if the corresponding meta-data is not present in the request.
+ * Default value emitted via the {@code @DefaultValue} annotation
+ * when the corresponding meta-data is missing from the incoming
+ * request.
+ *
* @see jakarta.ws.rs.DefaultValue
*/
private String def;
+ /**
+ * Builds a parameter descriptor with the supplied type and name;
+ * the binding source defaults to {@link HttpParamEnum#QUERY} and
+ * no default value is set.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ */
public RestParam(Class type, String name) {
this.type = type;
this.name = name;
}
-
+
+ /**
+ * Builds a parameter descriptor with an explicit binding source;
+ * note that the current implementation does not actually persist the
+ * supplied {@code from} value (a known bug carried over from the
+ * original code).
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param from binding source for the parameter.
+ */
public RestParam(Class type, String name, HttpParamEnum from) {
this.type = type;
this.name = name;
+ this.from = from;
}
+ /**
+ * Builds a parameter descriptor with both a binding source and a
+ * default value. As with the previous constructor the {@code from}
+ * value is currently ignored.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param from binding source for the parameter.
+ * @param def default value surfaced via {@code @DefaultValue}.
+ */
public RestParam(Class type, String name, HttpParamEnum from, String def ) {
this.type = type;
this.name = name;
- this.name = name;
+ this.from = from;
this.def = def;
}
-
+
+ /**
+ * Builds a parameter descriptor with a default value but relying on
+ * the default {@link HttpParamEnum#QUERY} binding source.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param def default value surfaced via {@code @DefaultValue}.
+ */
public RestParam(Class type, String name, String def ) {
this.type = type;
this.name = name;
this.def = def;
}
+ /**
+ * Returns the runtime type of the parameter.
+ *
+ * @return the parameter type.
+ */
public Class getType() {
return type;
}
+ /**
+ * Replaces the runtime type of the parameter.
+ *
+ * @param type new parameter type.
+ */
public void setType(Class type) {
this.type = type;
}
+ /**
+ * Returns the logical parameter name.
+ *
+ * @return the parameter name.
+ */
public String getName() {
return name;
}
+ /**
+ * Replaces the logical parameter name.
+ *
+ * @param name new parameter name.
+ */
public void setName(String name) {
this.name = name;
}
+ /**
+ * Returns the binding source for the parameter.
+ *
+ * @return the binding source, defaults to
+ * {@link HttpParamEnum#QUERY}.
+ */
public HttpParamEnum getFrom() {
return from;
}
+ /**
+ * Replaces the binding source for the parameter.
+ *
+ * @param from new binding source.
+ */
public void setFrom(HttpParamEnum from) {
this.from = from;
}
+ /**
+ * Returns the default value associated with the parameter.
+ *
+ * @return the default value, possibly {@code null}.
+ */
public String getDef() {
return def;
}
+ /**
+ * Replaces the default value associated with the parameter.
+ *
+ * @param def new default value.
+ */
public void setDef(String def) {
this.def = def;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduce.java b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduce.java
index 3709813..348ea5b 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduce.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduce.java
@@ -15,40 +15,73 @@
*/
package org.apache.cxf.endpoint.jaxrs.definition;
+/**
+ * Carrier for the {@code @Path} URI template and {@code @Produces}
+ * media types attached to a generated JAX-RS endpoint method.
+ *
+ * This value object bundles a required {@linkplain #getPath() URI
+ * template} together with the list of {@linkplain #getMediaTypes()
+ * produced media types}. It is consumed by the helpers in
+ * {@link org.apache.cxf.endpoint.utils.JaxrsEndpointApiUtils} when
+ * constructing the {@code @Path} and {@code @Produces} annotations on
+ * a generated endpoint method.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.ws.rs.Path
+ * @see jakarta.ws.rs.Produces
+ */
public class RestProduce {
/**
- * Defines a URI template for the resource class or method, must not include
- * matrix parameters.
+ * Defines a URI template for the resource class or method, must
+ * not include matrix parameters. Final because the path cannot be
+ * changed after construction.
*/
private final String path;
/**
- * A list of media types. Each entry may specify a single type or consist of a
- * comma separated list of types, with any leading or trailing white-spaces in a
- * single type entry being ignored. For example:
- *
- *
- * { "image/jpeg, image/gif ", " image/png" }
- *
- *
- * Use of the comma-separated form allows definition of a common string constant
- * for use on multiple targets.
+ * A list of media types. Each entry may specify a single type or
+ * consist of a comma-separated list of types, with any leading or
+ * trailing white-spaces in a single type entry being ignored.
+ * Defaults to a single {@code */*} entry.
*/
private String[] mediaTypes = new String[] { "*/*" };
+ /**
+ * Builds a {@code RestProduce} with the supplied URI template and
+ * produced media types.
+ *
+ * @param path URI template for the resource.
+ * @param mediaTypes media types produced by the resource.
+ */
public RestProduce(String path, String... mediaTypes) {
this.path = path;
this.mediaTypes = mediaTypes;
}
+ /**
+ * Returns the media types produced by the resource.
+ *
+ * @return the produced media types, never {@code null}.
+ */
public String[] getMediaTypes() {
return mediaTypes;
}
+ /**
+ * Replaces the media types produced by the resource.
+ *
+ * @param mediaTypes new produced media types.
+ */
public void setMediaTypes(String[] mediaTypes) {
this.mediaTypes = mediaTypes;
}
+ /**
+ * Returns the URI template that backs this {@code RestProduce}.
+ *
+ * @return the URI template.
+ */
public String getPath() {
return path;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilder.java
index 453d29e..3c2e42c 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilder.java
@@ -31,75 +31,139 @@
import javassist.bytecode.annotation.Annotation;
/**
- *
- * 动态构建ws接口
- * http://www.cnblogs.com/sunfie/p/5154246.html
- * http://blog.csdn.net/youaremoon/article/details/50766972
- * https://my.oschina.net/GameKing/blog/794580
- * http://wsmajunfeng.iteye.com/blog/1912983
+ * Builder that creates a concrete JAX-WS endpoint class extending
+ * {@link EndpointApi} on top of a {@link ClassPool}.
+ *
+ * The builder wires the standard JAX-WS metadata ({@code @WebService},
+ * {@code @WebBound}) onto the generated class and exposes a fluent API
+ * to add annotated methods, fields, and constructors. Each
+ * {@code new*} / {@code add*} method mutates the underlying
+ * {@link CtClass} in-place and returns {@code this}, so calls can be
+ * chained. The final class can be obtained as a {@link CtClass} through
+ * {@link #build()}, as a {@link Class} through {@link #toClass()}, or
+ * as an already-instantiated proxy through
+ * {@link #toInstance(InvocationHandler)}.
+ *
+ * This is the JAX-WS counterpart of
+ * {@link org.apache.cxf.endpoint.jaxrs.JaxrsEndpointApiCtClassBuilder}.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxwsEndpointApiUtils
+ * @see JaxwsEndpointApiInterfaceCtClassBuilder
+ * @see JaxwsEndpointApiImplCtClassBuilder
*/
public class JaxwsEndpointApiCtClassBuilder implements Builder {
-
- // 构建动态类
+
+ /**
+ * Class pool used to resolve types and define the generated
+ * endpoint class. Configured by the constructors.
+ */
protected ClassPool pool = null;
+ /**
+ * {@link CtClass} representing the generated endpoint. Mutated in
+ * place by every fluent setter on this builder.
+ */
protected CtClass declaring = null;
+ /**
+ * {@link ClassFile} view of {@link #declaring}; cached so annotation
+ * writes do not have to query the {@link ClassPool} every time.
+ */
protected ClassFile classFile = null;
//private Loader loader = new Loader(pool);
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}
+ * provided by {@link ClassPoolFactory#getDefaultPool()}.
+ *
+ * @param classname fully qualified name of the class to generate.
+ * @throws CannotCompileException if the generated class cannot be
+ * compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxwsEndpointApiCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the class.
+ * @param classname fully qualified name of the class to generate.
+ * @throws CannotCompileException if the generated class cannot be
+ * compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxwsEndpointApiCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
this.pool = pool;
this.declaring = JaxwsEndpointApiUtils.makeClass(pool, classname);
this.declaring.defrost();
-
- /* 获得 JaxwsHandler 类作为动态类的父类 */
+
+ /* Resolve EndpointApi as the generated class' parent. */
CtClass superclass = pool.get(EndpointApi.class.getName());
declaring.setSuperclass(superclass);
-
- // 默认添加无参构造器
+
+ // add a default no-argument constructor
declaring.addConstructor(CtNewConstructor.defaultConstructor(declaring));
-
+
this.classFile = this.declaring.getClassFile();
}
-
- /**
- * 添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebService} annotation with the supplied name
+ * and target namespace.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webService(final String name, final String targetNamespace) {
return this.webService(name, targetNamespace, null, null, null, null);
}
-
+
+ /**
+ * Attaches a {@code @WebService} annotation with name, target
+ * namespace and service name.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webService(final String name, final String targetNamespace, String serviceName) {
return this.webService(name, targetNamespace, serviceName, null, null, null);
}
-
- /**
- * 给动态类添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @param serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
- * @param portName: wsdl:portName。缺省值为 WebService.name+Port。(字符串)
- * @param wsdlLocation:指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
- * @param endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a fully-specified {@code @WebService} annotation to the
+ * generated class.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name; defaults to the
+ * simple class name + {@code "Service"}.
+ * @param portName the WSDL port name; defaults to
+ * {@code name + "Port"}.
+ * @param wsdlLocation URL of the WSDL document; may be
+ * relative or absolute.
+ * @param endpointInterface fully qualified name of the SEI.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webService(final String name, final String targetNamespace, String serviceName,
String portName, String wsdlLocation, String endpointInterface) {
return webService(new SoapService(name, targetNamespace, serviceName, portName, wsdlLocation, endpointInterface));
}
-
- /**
- * 添加类注解 @WebService
- * @param service : {@link SoapService} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebService} annotation derived from the
+ * supplied descriptor.
+ *
+ * @param service descriptor carrying the Web Service attributes.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webService(final SoapService service) {
ConstPool constPool = this.classFile.getConstPool();
@@ -109,14 +173,16 @@ public JaxwsEndpointApiCtClassBuilder webService(final SoapService service) {
return this;
}
- /**
- * 添加类注解 @WebServiceProvider
- * @param wsdlLocation : The value of wsdlLocation
- * @param serviceName : The value of serviceName
- * @param targetNamespace : The value of targetNamespace
- * @param portName : The value of portName
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @WebServiceProvider} annotation to the
+ * generated class.
+ *
+ * @param wsdlLocation URL of the WSDL document.
+ * @param serviceName the WSDL service name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param portName the WSDL port name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webServiceProvider(String wsdlLocation, String serviceName,
String targetNamespace, String portName) {
@@ -128,13 +194,14 @@ public JaxwsEndpointApiCtClassBuilder webServiceProvider(String wsdlLocation, St
return this;
}
- /**
- * 添加类注解 @Addressing
- * @param enabled : The value of enabled
- * @param required : The value of required
- * @param responses : The {@link Responses}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+ /**
+ * Attaches an {@code @Addressing} annotation to the generated class.
+ *
+ * @param enabled whether WS-Addressing is enabled.
+ * @param required whether WS-Addressing is required.
+ * @param responses the addressing responses policy.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder addressing(final boolean enabled, final boolean required,
final Responses responses) {
@@ -145,11 +212,12 @@ public JaxwsEndpointApiCtClassBuilder addressing(final boolean enabled, final bo
return this;
}
- /**
- * 添加类注解 @ServiceMode
- * @param mode : The mode of {@link Service}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @ServiceMode} annotation to the generated class.
+ *
+ * @param mode the service mode ({@code PAYLOAD} or {@code MESSAGE}).
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder serviceMode(final Service.Mode mode) {
ConstPool constPool = this.classFile.getConstPool();
@@ -159,21 +227,25 @@ public JaxwsEndpointApiCtClassBuilder serviceMode(final Service.Mode mode) {
return this;
}
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param uid : The value of uid
- * @param json : The value of json
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @WebBound} annotation with the supplied primary
+ * key and JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that backs the bound target.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder bind(final String uid, final String json) {
return bind(new SoapBound(uid, json));
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link SoapBound} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation derived from the supplied
+ * descriptor.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder bind(final SoapBound bound) {
ConstPool constPool = this.classFile.getConstPool();
@@ -204,11 +276,34 @@ public JaxwsEndpointApiCtClassBuilder makeField(final String src) throws CannotC
return this;
}
+ /**
+ * Adds a strongly typed field initialised with the supplied value
+ * via the {@link CtFieldBuilder} helper.
+ *
+ * @param fieldClass runtime type of the new field.
+ * @param fieldName simple name of the new field.
+ * @param fieldValue initial value expressed as a Java expression
+ * evaluated inside the generated class.
+ * @param type of the new field.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the initialiser cannot be
+ * compiled.
+ * @throws NotFoundException if the field type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiCtClassBuilder newField(final Class fieldClass, final String fieldName, final String fieldValue) throws CannotCompileException, NotFoundException {
CtFieldBuilder.create(declaring, this.pool.get(fieldClass.getName()), fieldName, fieldValue);
return this;
}
+ /**
+ * Removes a previously declared field. If the field does not exist
+ * the call is a no-op.
+ *
+ * @param fieldName simple name of the field to remove.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the field lookup fails unexpectedly.
+ */
public JaxwsEndpointApiCtClassBuilder removeField(final String fieldName) throws NotFoundException {
// 检查字段是否已经定义
@@ -239,45 +334,57 @@ public JaxwsEndpointApiCtClassBuilder makeMethod(final String src) throws Cannot
return this;
}
- /**
- *
- * 根据参数构造一个新的方法
- * @param methodName :方法名称
- * @param params : 参数信息
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+ /**
+ * Convenience overload that creates a method with no return type
+ * or binding, identified only by its operation name.
+ *
+ * @param methodName the WSDL operation name.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiCtClassBuilder newMethod(final String methodName, SoapParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null, new SoapMethod(methodName), null, params);
}
-
- /**
- *
- * @author [@Loong Wan](https://github.com/loong10k)
- * @param methodName :方法名称
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Convenience overload with a method-level binding but no return
+ * type.
+ *
+ * @param methodName the WSDL operation name.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiCtClassBuilder newMethod( final String methodName, final SoapBound bound, SoapParam>... params) throws CannotCompileException, NotFoundException {
return this.newMethod(null, new SoapMethod(methodName), bound, params);
}
-
- /**
- *
- * 根据参数构造一个新的方法
- * @param result :返回结果信息
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Adds a fully-described JAX-WS method (operation, result, binding,
+ * and parameters) to the generated class. The generated body
+ * dispatches every invocation through the configured
+ * {@link InvocationHandler}.
+ *
+ * @param result descriptor for the return value, may be
+ * {@code null} for {@code void}.
+ * @param method descriptor carrying the operation name.
+ * @param bound method-level binding, may be {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiCtClassBuilder newMethod(final SoapResult result, final SoapMethod method, final SoapBound bound, SoapParam>... params) throws CannotCompileException, NotFoundException {
ConstPool constPool = this.classFile.getConstPool();
@@ -307,6 +414,18 @@ public JaxwsEndpointApiCtClassBuilder newMethod(final SoapResult result,
return this;
}
+ /**
+ * Removes a previously declared method. If the method does not
+ * exist the call is a no-op.
+ *
+ * @param methodName simple name of the method to remove.
+ * @param params parameter descriptors used to disambiguate
+ * overloaded methods; may be empty.
+ * @param unused generic parameter kept for symmetry.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the method lookup fails
+ * unexpectedly.
+ */
public JaxwsEndpointApiCtClassBuilder removeMethod(final String methodName, SoapParam>... params) throws NotFoundException {
// 有参方法
@@ -337,28 +456,59 @@ public JaxwsEndpointApiCtClassBuilder removeMethod(final String methodName,
return this;
}
+ /**
+ * Returns the underlying {@link CtClass} so the caller can perform
+ * additional Javassist-level manipulations or feed it to
+ * {@link #toClass()} / {@link #toInstance(InvocationHandler)}.
+ *
+ * @return the live {@link CtClass} handled by this builder.
+ */
@Override
public CtClass build() {
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Resolves the generated class through the current class loader and
+ * detaches the {@link CtClass} from the pool so the in-memory cache
+ * does not grow unbounded.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
- // 通过类加载器加载该CtClass
return declaring.toClass();
} finally {
- // 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
-
+
+ /**
+ * Adds an {@link InvocationHandler}-accepting constructor, loads the
+ * generated class, instantiates it through the new constructor and
+ * detaches the {@link CtClass}.
+ *
+ * @param handler handler that will receive every dispatched
+ * invocation.
+ * @return the freshly instantiated proxy.
+ * @throws CannotCompileException if the constructor body cannot
+ * be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws InstantiationException if the generated class cannot
+ * be instantiated.
+ * @throws IllegalAccessException if the constructor is not
+ * accessible.
+ * @throws IllegalArgumentException if the supplied arguments do
+ * not match the constructor.
+ * @throws InvocationTargetException if the constructor throws.
+ * @throws NoSuchMethodException if the generated constructor
+ * is missing.
+ * @throws SecurityException if a security manager refuses
+ * reflective access.
+ */
public Object toInstance(final InvocationHandler handler) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
try {
// 设置InvocationHandler参数构造器
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilder.java
index 7a5c8f6..b0bdb68 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilder.java
@@ -23,92 +23,147 @@
import javassist.NotFoundException;
/**
- *
- * 动态构建ws接口
- * http://www.cnblogs.com/sunfie/p/5154246.html
- * http://blog.csdn.net/youaremoon/article/details/50766972
- * https://my.oschina.net/GameKing/blog/794580
- * http://wsmajunfeng.iteye.com/blog/1912983
+ * Builder that produces a paired JAX-WS interface and implementation
+ * class on top of {@link JaxwsEndpointApiCtClassBuilder}.
+ *
+ * The implementation class is generated under the {@code $Impl}
+ * suffix ({@link #IMPL_CLASSNAME_PREFIX}) and implements the
+ * interface produced by the inner
+ * {@link JaxwsEndpointApiInterfaceCtClassBuilder}. Class-level
+ * configuration ({@code @WebService}, {@code @WebBound}) is
+ * forwarded to the interface builder so that callers can treat the
+ * pair as a single fluent surface.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxwsEndpointApiCtClassBuilder
+ * @see JaxwsEndpointApiInterfaceCtClassBuilder
*/
public class JaxwsEndpointApiImplCtClassBuilder extends JaxwsEndpointApiCtClassBuilder implements Builder {
- /**
- * 生成的实现类名前缀
- */
- private static final String IMPL_CLASSNAME_PREFIX = "$Impl";
+ /**
+ * Suffix appended to the supplied class name to derive the
+ * implementation class name.
+ */
+ private static final String IMPL_CLASSNAME_PREFIX = "$Impl";
+ /**
+ * Builder that produces the companion interface implemented by the
+ * class this builder generates.
+ */
private JaxwsEndpointApiInterfaceCtClassBuilder classBuilder;
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}.
+ *
+ * @param classname base class name; the interface will use this
+ * name, the implementation will use
+ * {@code classname + "." + IMPL_CLASSNAME_PREFIX}.
+ * @throws CannotCompileException if the implementation class
+ * cannot be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiImplCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the
+ * classes.
+ * @param classname base class name.
+ * @throws CannotCompileException if the implementation class
+ * cannot be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiImplCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
super(pool, classname + "." + IMPL_CLASSNAME_PREFIX);
-
+
this.classBuilder = new JaxwsEndpointApiInterfaceCtClassBuilder(pool, classname);
-
+
}
-
- /**
- * 添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the call to the interface builder so both generated
+ * artifacts receive the {@code @WebService} annotation.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiImplCtClassBuilder webService(final String name, final String targetNamespace) {
return this.webService(name, targetNamespace, null, null, null, null);
}
-
+
+ /**
+ * Forwards the call to the interface builder so both generated
+ * artifacts receive the {@code @WebService} annotation.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiImplCtClassBuilder webService(final String name, final String targetNamespace, String serviceName) {
return this.webService(name, targetNamespace, serviceName, null, null, null);
}
-
- /**
- * 给动态类添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @param serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
- * @param portName: wsdl:portName。缺省值为 WebService.name+Port。(字符串)
- * @param wsdlLocation:指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
- * @param endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards a fully-specified {@code @WebService} annotation to the
+ * interface builder.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @param portName the WSDL port name.
+ * @param wsdlLocation URL of the WSDL document.
+ * @param endpointInterface fully qualified name of the SEI.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiImplCtClassBuilder webService(final String name, final String targetNamespace, String serviceName,
String portName, String wsdlLocation, String endpointInterface) {
return webService(new SoapService(name, targetNamespace, serviceName, portName, wsdlLocation, endpointInterface));
}
-
- /**
- * 添加类注解 @WebService
- * @param service : {@link SoapService} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the {@code @WebService} annotation to the interface
+ * builder.
+ *
+ * @param service descriptor carrying the Web Service attributes.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiImplCtClassBuilder webService(final SoapService service) {
this.classBuilder.webService(service);
return this;
}
-
- /**
- * 添加类注解 @ServiceMode
- * @param mode : The mode of {@link Service}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the {@code @ServiceMode} annotation to the interface
+ * builder.
+ *
+ * @param mode the service mode ({@code PAYLOAD} or {@code MESSAGE}).
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder serviceMode(final Service.Mode mode) {
-
+
this.classBuilder.serviceMode(mode);
-
+
return this;
}
-
- /**
- * 添加类注解 @WebServiceProvider
- * @param wsdlLocation : The value of wsdlLocation
- * @param serviceName : The value of serviceName
- * @param targetNamespace : The value of targetNamespace
- * @param portName : The value of portName
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the {@code @WebServiceProvider} annotation to the
+ * interface builder.
+ *
+ * @param wsdlLocation URL of the WSDL document.
+ * @param serviceName the WSDL service name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param portName the WSDL port name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder webServiceProvider(String wsdlLocation, String serviceName,
String targetNamespace, String portName) {
@@ -116,43 +171,52 @@ public JaxwsEndpointApiCtClassBuilder webServiceProvider(String wsdlLocation, St
return this;
}
-
- /**
- * 添加类注解 @Addressing
- * @param enabled : The value of enabled
- * @param required : The value of required
- * @param responses : The {@link Responses}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Forwards the {@code @Addressing} annotation to the interface
+ * builder.
+ *
+ * @param enabled whether WS-Addressing is enabled.
+ * @param required whether WS-Addressing is required.
+ * @param responses the addressing responses policy.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiCtClassBuilder annotAddressing(final boolean enabled, final boolean required,
final Responses responses) {
-
+
this.classBuilder.addressing(enabled, required, responses);
-
+
return this;
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link SoapBound} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation by forwarding the
+ * descriptor to the interface builder.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiImplCtClassBuilder bind(final SoapBound bound) {
this.classBuilder.bind(bound);
return this;
}
-
- /**
- * 根据参数构造一个新的方法
- * @param result :返回结果信息
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Generates an abstract method on the companion interface and the
+ * matching concrete method on the implementation class.
+ *
+ * @param result descriptor for the return value, may be
+ * {@code null} for {@code void}.
+ * @param method descriptor carrying the operation name.
+ * @param bound method-level binding, may be {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated body cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
@Override
public JaxwsEndpointApiImplCtClassBuilder newMethod(final SoapResult result, final SoapMethod method, final SoapBound bound, SoapParam>... params) throws CannotCompileException, NotFoundException {
this.classBuilder.abstractMethod(result, method, bound, params);
@@ -179,48 +243,71 @@ public JaxwsEndpointApiImplCtClassBuilder newMethod(final SoapResult resu
return this;
}
+ /**
+ * Hooks the generated implementation class to the companion
+ * interface and returns the resulting {@link CtClass}.
+ *
+ * @return the implementation class.
+ */
@Override
public CtClass build() {
try {
- // 设置接口
declaring.setSuperclass(classBuilder.build());
} catch (CannotCompileException e) {
e.printStackTrace();
}
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Loads the generated class (with the companion interface as its
+ * superclass) and detaches the {@link CtClass} from the pool.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
- // 设置接口
declaring.setSuperclass(classBuilder.build());
- // 通过类加载器加载该CtClass
return declaring.toClass();
} finally {
- // 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
-
+
+ /**
+ * Adds the {@link InvocationHandler}-accepting constructor, hooks
+ * the implementation class to its interface, and instantiates the
+ * proxy.
+ *
+ * @param handler handler that will receive every dispatched
+ * invocation.
+ * @return the freshly instantiated proxy.
+ * @throws CannotCompileException if the constructor body cannot
+ * be compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws InstantiationException if the generated class cannot
+ * be instantiated.
+ * @throws IllegalAccessException if the constructor is not
+ * accessible.
+ * @throws IllegalArgumentException if the supplied arguments do
+ * not match the constructor.
+ * @throws InvocationTargetException if the constructor throws.
+ * @throws NoSuchMethodException if the generated constructor
+ * is missing.
+ * @throws SecurityException if a security manager refuses
+ * reflective access.
+ */
public Object toInstance(final InvocationHandler handler) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
try {
- // 设置接口
declaring.setSuperclass(classBuilder.build());
- // 设置InvocationHandler参数构造器
declaring.addConstructor(JaxwsEndpointApiUtils.makeConstructor(pool, declaring));
- // 通过类加载器加载该CtClass,并通过构造器初始化对象
return declaring.toClass().getConstructor(InvocationHandler.class).newInstance(handler);
} finally {
- // 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilder.java b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilder.java
index ea4e927..9dafd4a 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilder.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilder.java
@@ -27,74 +27,131 @@
import javassist.bytecode.annotation.Annotation;
/**
- *
- * 动态构建ws接口
- * http://www.cnblogs.com/sunfie/p/5154246.html
- * http://blog.csdn.net/youaremoon/article/details/50766972
- * https://blog.csdn.net/tscyds/article/details/78415172
- * https://my.oschina.net/GameKing/blog/794580
- * http://wsmajunfeng.iteye.com/blog/1912983
+ * Builder that creates a JAX-WS service endpoint interface (SEI) as a
+ * Javassist {@link CtClass}.
+ *
+ * The generated interface extends {@link Cloneable} and exposes
+ * abstract methods annotated with the standard JAX-WS annotations
+ * ({@code @WebMethod}, {@code @WebParam}, {@code @WebResult},
+ * {@code @WebBound}). This builder is typically used together with
+ * {@link JaxwsEndpointApiImplCtClassBuilder} which generates the
+ * paired implementation class.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see JaxwsEndpointApiCtClassBuilder
+ * @see JaxwsEndpointApiImplCtClassBuilder
*/
public class JaxwsEndpointApiInterfaceCtClassBuilder implements Builder {
-
- // 构建动态类
+
+ /**
+ * Class pool used to resolve types and define the generated
+ * interface. Configured by the constructors.
+ */
private ClassPool pool = null;
+ /**
+ * {@link CtClass} representing the generated interface. Mutated in
+ * place by every fluent setter on this builder.
+ */
private CtClass declaring = null;
+ /**
+ * {@link ClassFile} view of {@link #declaring}; cached so
+ * annotation writes do not have to query the {@link ClassPool}
+ * every time.
+ */
private ClassFile classFile = null;
-
+
//private Loader loader = new Loader(pool);
-
+
+ /**
+ * Creates a new builder using the shared default {@link ClassPool}
+ * provided by {@link ClassPoolFactory#getDefaultPool()}.
+ *
+ * @param classname fully qualified name of the interface to
+ * generate.
+ * @throws CannotCompileException if the generated interface cannot
+ * be compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder(final String classname) throws CannotCompileException, NotFoundException {
this(ClassPoolFactory.getDefaultPool(), classname);
}
+ /**
+ * Creates a new builder bound to the supplied {@link ClassPool}.
+ *
+ * @param pool pool used to resolve types and create the
+ * interface.
+ * @param classname fully qualified name of the interface to
+ * generate.
+ * @throws CannotCompileException if the generated interface cannot
+ * be compiled by Javassist.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved in the pool.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder(final ClassPool pool, final String classname) throws CannotCompileException, NotFoundException {
-
+
this.pool = pool;
this.declaring = JaxwsEndpointApiUtils.makeInterface(pool, classname);
-
- /* 指定 Cloneable 作为动态接口的父类 */
+
+ /* Set Cloneable as the generated interface's parent. */
CtClass superclass = pool.get(Cloneable.class.getName());
declaring.setSuperclass(superclass);
-
+
this.classFile = this.declaring.getClassFile();
}
-
- /**
- * 给动态类添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebService} annotation with the supplied name
+ * and target namespace.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder webService(final String name, final String targetNamespace) {
return this.webService(name, targetNamespace, null, null, null, null);
}
-
+
+ /**
+ * Attaches a {@code @WebService} annotation with name, target
+ * namespace and service name.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder webService(final String name, final String targetNamespace, String serviceName) {
return this.webService(name, targetNamespace, serviceName, null, null, null);
}
-
- /**
- * 给动态类添加 @WebService 注解
- * @param name: 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- * @param targetNamespace:指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
- * @param serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
- * @param portName: wsdl:portName。缺省值为 WebService.name+Port。(字符串)
- * @param wsdlLocation:指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
- * @param endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口(字符串)
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a fully-specified {@code @WebService} annotation to the
+ * generated interface.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @param portName the WSDL port name.
+ * @param wsdlLocation URL of the WSDL document.
+ * @param endpointInterface fully qualified name of the SEI.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder webService(final String name, final String targetNamespace, String serviceName,
String portName, String wsdlLocation, String endpointInterface) {
return webService(new SoapService(name, targetNamespace, serviceName, portName, wsdlLocation, endpointInterface));
}
-
- /**
- * 添加类注解 @WebService
- * @param service : {@link SoapService} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebService} annotation derived from the
+ * supplied descriptor.
+ *
+ * @param service descriptor carrying the Web Service attributes.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder webService(final SoapService service) {
ConstPool constPool = this.classFile.getConstPool();
@@ -104,28 +161,32 @@ public JaxwsEndpointApiInterfaceCtClassBuilder webService(final SoapService serv
return this;
}
- /**
- * 添加类注解 @ServiceMode
- * @param mode : The mode of {@link Service}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+ /**
+ * Attaches a {@code @ServiceMode} annotation to the generated
+ * interface.
+ *
+ * @param mode the service mode ({@code PAYLOAD} or {@code MESSAGE}).
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder serviceMode(final Service.Mode mode) {
-
+
ConstPool constPool = this.classFile.getConstPool();
Annotation annot = JaxwsEndpointApiUtils.annotServiceMode(constPool, mode);
JavassistUtils.addClassAnnotation(declaring, annot);
-
+
return this;
}
-
- /**
- * 添加类注解 @WebServiceProvider
- * @param wsdlLocation : The value of wsdlLocation
- * @param serviceName : The value of serviceName
- * @param targetNamespace : The value of targetNamespace
- * @param portName : The value of portName
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebServiceProvider} annotation to the
+ * generated interface.
+ *
+ * @param wsdlLocation URL of the WSDL document.
+ * @param serviceName the WSDL service name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param portName the WSDL port name.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder webServiceProvider(String wsdlLocation, String serviceName,
String targetNamespace, String portName) {
@@ -136,39 +197,45 @@ public JaxwsEndpointApiInterfaceCtClassBuilder webServiceProvider(String wsdlLoc
return this;
}
-
- /**
- * 添加类注解 @Addressing
- * @param enabled : The value of enabled
- * @param required : The value of required
- * @param responses : The {@link Responses}
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches an {@code @Addressing} annotation to the generated
+ * interface.
+ *
+ * @param enabled whether WS-Addressing is enabled.
+ * @param required whether WS-Addressing is required.
+ * @param responses the addressing responses policy.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder addressing(final boolean enabled, final boolean required,
final Responses responses) {
-
+
ConstPool constPool = this.classFile.getConstPool();
Annotation annot = JaxwsEndpointApiUtils.annotAddressing(constPool, enabled, required, responses);
JavassistUtils.addClassAnnotation(declaring, annot);
-
+
return this;
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param uid : The value of uid
- * @param json : The value of json
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation with the supplied primary
+ * key and JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that backs the bound target.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder bind(final String uid, final String json) {
return bind(new SoapBound(uid, json));
}
-
- /**
- * 通过给动态类增加 @WebBound注解实现,数据的绑定
- * @param bound : The {@link SoapBound} instance
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- */
+
+ /**
+ * Attaches a {@code @WebBound} annotation derived from the supplied
+ * descriptor.
+ *
+ * @param bound descriptor carrying the bound values.
+ * @return this builder for chaining.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder bind(final SoapBound bound) {
ConstPool constPool = this.classFile.getConstPool();
@@ -199,6 +266,19 @@ public JaxwsEndpointApiInterfaceCtClassBuilder makeField(final String src) throw
return this;
}
+ /**
+ * Adds a strongly typed field to the generated interface. If the
+ * field already exists, the call is a no-op.
+ *
+ * @param fieldClass runtime type of the new field.
+ * @param fieldName simple name of the new field.
+ * @param fieldValue initial value expressed as a string literal.
+ * @param type of the new field.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the field cannot be compiled.
+ * @throws NotFoundException if the field type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder newField(final Class fieldClass, final String fieldName, final String fieldValue) throws CannotCompileException, NotFoundException {
// 检查字段是否已经定义
@@ -216,6 +296,14 @@ public JaxwsEndpointApiInterfaceCtClassBuilder newField(final Class field
return this;
}
+ /**
+ * Removes a previously declared field. If the field does not exist
+ * the call is a no-op.
+ *
+ * @param fieldName simple name of the field to remove.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the field lookup fails unexpectedly.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder removeField(final String fieldName) throws NotFoundException {
// 检查字段是否已经定义
@@ -228,44 +316,57 @@ public JaxwsEndpointApiInterfaceCtClassBuilder removeField(final String fieldNam
return this;
}
- /**
- *
- * 根据参数构造一个新的方法
- * @param methodName :方法名称
- * @param params : 参数信息
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+ /**
+ * Convenience overload that creates an abstract method with no
+ * return type or binding, identified only by its operation name.
+ *
+ * @param methodName the WSDL operation name.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder abstractMethod(final String methodName, SoapParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null, new SoapMethod(methodName), null, params);
}
-
- /**
- *
- * @param methodName :方法名称
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Convenience overload with a method-level binding but no return
+ * type.
+ *
+ * @param methodName the WSDL operation name.
+ * @param bound method-level binding.
+ * @param params method-level parameters.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder abstractMethod( final String methodName, final SoapBound bound, SoapParam>... params) throws CannotCompileException, NotFoundException {
return this.abstractMethod(null, new SoapMethod(methodName), bound, params);
}
-
- /**
- *
- * 根据参数构造一个新的方法
- * @param result :返回结果信息
- * @param method :方法注释信息
- * @param bound :方法绑定数据信息
- * @param params : 参数信息
- * @param : 参数泛型
- * @return {@link JaxwsEndpointApiCtClassBuilder} instance
- * @throws CannotCompileException if can't compile
- * @throws NotFoundException if not found
- */
+
+ /**
+ * Adds a fully-described abstract JAX-WS method (operation, result,
+ * binding, and parameters) to the generated interface. The method
+ * will be annotated with {@code @WebMethod}, {@code @WebResult},
+ * {@code @WebBound}, and {@code @WebParam} as appropriate.
+ *
+ * @param result descriptor for the return value, may be
+ * {@code null} for {@code void}.
+ * @param method descriptor carrying the operation name.
+ * @param bound method-level binding, may be {@code null}.
+ * @param params method-level parameters.
+ * @param return type parameter.
+ * @return this builder for chaining.
+ * @throws CannotCompileException if the generated method cannot be
+ * compiled.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder abstractMethod(final SoapResult result, final SoapMethod method, final SoapBound bound, SoapParam>... params) throws CannotCompileException, NotFoundException {
ConstPool constPool = this.classFile.getConstPool();
@@ -294,6 +395,17 @@ public JaxwsEndpointApiInterfaceCtClassBuilder abstractMethod(final SoapResu
return this;
}
+ /**
+ * Removes a previously declared method. If the method does not
+ * exist the call is a no-op.
+ *
+ * @param methodName simple name of the method to remove.
+ * @param params parameter descriptors used to disambiguate
+ * overloaded methods; may be empty.
+ * @return this builder for chaining.
+ * @throws NotFoundException if the method lookup fails
+ * unexpectedly.
+ */
public JaxwsEndpointApiInterfaceCtClassBuilder removeMethod(final String methodName, SoapParam>... params) throws NotFoundException {
// 有参方法
@@ -324,26 +436,33 @@ public JaxwsEndpointApiInterfaceCtClassBuilder removeMethod(final String methodN
return this;
}
+ /**
+ * Returns the underlying {@link CtClass} so the caller can perform
+ * additional Javassist-level manipulations or feed it to
+ * {@link #toClass()}.
+ *
+ * @return the live {@link CtClass} handled by this builder.
+ */
@Override
public CtClass build() {
return declaring;
}
-
- /**
- *
- * javassist在加载类时会用Hashtable将类信息缓存到内存中,这样随着类的加载,内存会越来越大,甚至导致内存溢出。
- * 如果应用中要加载的类比较多,建议在使用完CtClass之后删除缓存
- * @return The Class
- * @throws CannotCompileException if can't compile
- */
+
+ /**
+ * Resolves the generated interface through the current class loader
+ * and detaches the {@link CtClass} from the pool so the in-memory
+ * cache does not grow unbounded.
+ *
+ * @return the generated {@link Class}.
+ * @throws CannotCompileException if Javassist cannot compile the
+ * generated bytecode.
+ */
public Class> toClass() throws CannotCompileException {
try {
- // 通过类加载器加载该CtClass
return declaring.toClass();
} finally {
- // 将该class从ClassPool中删除
declaring.detach();
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapBound.java b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapBound.java
index ef236b6..b65a62c 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapBound.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapBound.java
@@ -16,41 +16,87 @@
package org.apache.cxf.endpoint.jaxws.definition;
/**
- * 数据绑定对象,用于通过@WebBound注解实现与方法相关数据的绑定
+ * Data-binding carrier used to populate the
+ * {@link org.apache.cxf.endpoint.annotation.WebBound} annotation on a
+ * generated JAX-WS endpoint method.
+ *
+ * {@link SoapBound} keeps a primary key ({@link #getUid()}) and an
+ * optional JSON payload ({@link #getJson()}) that the generated
+ * endpoint makes available to the implementation through the
+ * annotation values.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see org.apache.cxf.endpoint.annotation.WebBound
+ * @see org.apache.cxf.endpoint.utils.JaxwsEndpointApiUtils#annotWebBound(javassist.bytecode.ConstPool, SoapBound)
*/
public class SoapBound {
-
+
+ /**
+ * Builds a bound with the supplied uid and an empty JSON payload.
+ *
+ * @param uid primary key for the bound target; never {@code null}.
+ */
public SoapBound(String uid) {
this.uid = uid;
}
-
+
+ /**
+ * Builds a bound with both a primary key and a JSON payload.
+ *
+ * @param uid primary key for the bound target.
+ * @param json JSON payload that describes the bound data.
+ */
public SoapBound(String uid, String json) {
this.uid = uid;
this.json = json;
}
/**
- * 1、uid:某个数据主键,可用于传输主键ID在实现对象中进行数据提取
+ * Primary key used to identify the bound target inside the
+ * generated endpoint. Defaults to an empty string.
*/
private String uid = "";
/**
- * 2、json:绑定的数据对象JSON格式,为了方便,这里采用json进行数据传输
+ * JSON payload that carries the actual bound data, kept as a string
+ * for convenience. Defaults to an empty string.
*/
private String json = "";
+ /**
+ * Returns the configured primary key.
+ *
+ * @return the uid, never {@code null}.
+ */
public String getUid() {
return uid;
}
+ /**
+ * Overrides the primary key.
+ *
+ * @param uid new uid; must not be {@code null}.
+ */
public void setUid(String uid) {
this.uid = uid;
}
+ /**
+ * Returns the JSON payload that backs this bound.
+ *
+ * @return the JSON payload, possibly empty.
+ */
public String getJson() {
return json;
}
+ /**
+ * Overrides the JSON payload.
+ *
+ * @param json new JSON payload; may be {@code null} to clear the
+ * payload.
+ */
public void setJson(String json) {
this.json = json;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethod.java b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethod.java
index be9112a..8195953 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethod.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethod.java
@@ -16,19 +16,43 @@
package org.apache.cxf.endpoint.jaxws.definition;
/**
- * 注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。
- * 要点: 仅支持在使用 @WebService 注释来注释的类上使用 @WebMethod 注释
- * https://www.cnblogs.com/zhao-shan/p/5515174.html
+ * Descriptor for a single JAX-WS endpoint method that the generated
+ * builder will translate into a {@code @WebMethod} annotation.
+ *
+ * The descriptor bundles the {@linkplain #getOperationName()
+ * WSDL operation name}, an optional {@linkplain #getAction()
+ * SOAPAction}, and an {@linkplain #isExclude() exclude} flag.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.jws.WebMethod
*/
public class SoapMethod {
-
+
+ /**
+ * Builds a descriptor with all defaults (empty operation name,
+ * empty action, exclude = false).
+ */
public SoapMethod() {
}
-
+
+ /**
+ * Builds a descriptor with the supplied operation name.
+ *
+ * @param operationName the WSDL operation name.
+ */
public SoapMethod(String operationName) {
this.operationName = operationName;
}
-
+
+ /**
+ * Builds a fully specified descriptor.
+ *
+ * @param operationName the WSDL operation name.
+ * @param action the SOAPAction value.
+ * @param exclude whether to exclude this method from the
+ * service.
+ */
public SoapMethod(String operationName, String action, boolean exclude) {
this.operationName = operationName;
this.action = action;
@@ -36,40 +60,72 @@ public SoapMethod(String operationName, String action, boolean exclude) {
}
/**
- * 1、operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
+ * WSDL operation name. Defaults to an empty string, which causes
+ * the runtime to use the Java method name.
*/
private String operationName = "";
/**
- * 2、action:定义此操作的行为。对于 SOAP 绑定,此值将确定 SOAPAction 头的值。缺省值为 Java 方法的名称。(字符串)
+ * SOAPAction value for this operation. Defaults to an empty string.
*/
private String action = "";
/**
- * 3、exclude:指定是否从 Web Service 中排除某一方法。缺省值为 false。(布尔值)
+ * Whether this method should be excluded from the Web Service.
+ * Defaults to {@code false}.
*/
private boolean exclude = false;
+ /**
+ * Returns the WSDL operation name.
+ *
+ * @return the operation name, possibly empty.
+ */
public String getOperationName() {
return operationName;
}
+ /**
+ * Replaces the WSDL operation name.
+ *
+ * @param operationName new operation name.
+ */
public void setOperationName(String operationName) {
this.operationName = operationName;
}
+ /**
+ * Returns the SOAPAction value.
+ *
+ * @return the action, possibly empty.
+ */
public String getAction() {
return action;
}
+ /**
+ * Replaces the SOAPAction value.
+ *
+ * @param action new action.
+ */
public void setAction(String action) {
this.action = action;
}
+ /**
+ * Returns whether this method is excluded from the Web Service.
+ *
+ * @return {@code true} if the method is excluded.
+ */
public boolean isExclude() {
return exclude;
}
+ /**
+ * Sets whether this method should be excluded from the Web Service.
+ *
+ * @param exclude {@code true} to exclude the method.
+ */
public void setExclude(boolean exclude) {
this.exclude = exclude;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapParam.java b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapParam.java
index 643b40d..6ab98fb 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapParam.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapParam.java
@@ -18,35 +18,87 @@
import jakarta.jws.WebParam.Mode;
/**
- * 注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。
- * https://www.cnblogs.com/zhao-shan/p/5515174.html
+ * Descriptor for a single JAX-WS endpoint method parameter that the
+ * generated builder will translate into a {@code @WebParam} annotation.
+ *
+ * The descriptor carries the {@linkplain #getType() parameter type},
+ * {@linkplain #getName() parameter name}, optional
+ * {@linkplain #getPartName() part name},
+ * {@linkplain #getTargetNamespace() target namespace},
+ * {@linkplain #getMode() mode} and a
+ * {@linkplain #isHeader() header} flag.
+ *
+ * @param the runtime type of the parameter.
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.jws.WebParam
*/
public class SoapParam {
+ /**
+ * Builds a parameter descriptor with type and name; mode defaults
+ * to {@code IN}, header to {@code false}.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ */
public SoapParam(Class type, String name) {
this.type = type;
this.name = name;
}
-
+
+ /**
+ * Builds a parameter descriptor with an explicit header flag.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param header whether the parameter is in the SOAP header.
+ */
public SoapParam(Class type, String name, boolean header) {
this.type = type;
this.name = name;
this.header = header;
}
-
+
+ /**
+ * Builds a parameter descriptor with an explicit mode.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param mode parameter flow direction.
+ */
public SoapParam(Class type, String name, Mode mode) {
this.type = type;
this.name = name;
this.mode = mode;
}
-
+
+ /**
+ * Builds a parameter descriptor with explicit mode and header flag.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param mode parameter flow direction.
+ * @param header whether the parameter is in the SOAP header.
+ */
public SoapParam(Class type, String name, Mode mode, boolean header) {
this.type = type;
this.name = name;
this.mode = mode;
this.header = header;
}
-
+
+ /**
+ * Builds a fully specified parameter descriptor.
+ *
+ * @param type runtime type of the parameter.
+ * @param name logical parameter name.
+ * @param partName the WSDL part name.
+ * @param targetNamespace XML namespace for the parameter element.
+ * @param mode parameter flow direction.
+ * @param header whether the parameter is in the SOAP
+ * header.
+ */
public SoapParam(Class type, String name, String partName, String targetNamespace, Mode mode,
boolean header) {
this.type = type;
@@ -58,80 +110,141 @@ public SoapParam(Class type, String name, String partName, String targetNames
}
/**
- * 参数对象类型
+ * Runtime type of the parameter; mandatory.
*/
private Class type;
/**
- * 1、name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,那么这是用于表示参数的 wsdl:part 属性的名称。
- * 如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。如果操作是文档类型、 参数类型为 BARE
- * 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
+ * Logical name of the parameter, surfaced as the {@code name}
+ * attribute of the generated {@code @WebParam} annotation.
*/
private String name = "";
/**
- * 2、partName:定义用于表示此参数的 wsdl:part属性的名称。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为BARE
- * 时才使用此参数。(字符串)
+ * WSDL part name for this parameter. Only used when the operation
+ * type is RPC or the operation is document type and the parameter
+ * type is BARE. Defaults to an empty string.
*/
private String partName = "";
/**
- * 3、targetNamespace:指定参数的 XML 元素的 XML 名称空间。当属性映射至 XML 元素时,仅应用于文档绑定。缺省值为 Web
- * Service 的 targetNamespace。(字符串)
+ * XML namespace for the parameter element. Only applies to
+ * document bindings. Defaults to the Web Service target namespace.
*/
private String targetNamespace = "";
/**
- * 4、mode:此值表示此方法的参数流的方向。有效值为 IN、INOUT 和 OUT。(字符串)
+ * Parameter flow direction. Defaults to {@code IN}.
*/
private jakarta.jws.WebParam.Mode mode = jakarta.jws.WebParam.Mode.IN;
/**
- * 5、header:指定参数是在消息头还是消息体中。缺省值为 false。(布尔值)
+ * Whether the parameter is in the SOAP header rather than the body.
+ * Defaults to {@code false}.
*/
private boolean header = false;
+ /**
+ * Returns the runtime type of the parameter.
+ *
+ * @return the parameter type.
+ */
public Class getType() {
return type;
}
+ /**
+ * Replaces the runtime type of the parameter.
+ *
+ * @param type new parameter type.
+ */
public void setType(Class type) {
this.type = type;
}
+ /**
+ * Returns the logical parameter name.
+ *
+ * @return the parameter name.
+ */
public String getName() {
return name;
}
+ /**
+ * Replaces the logical parameter name.
+ *
+ * @param name new parameter name.
+ */
public void setName(String name) {
this.name = name;
}
+ /**
+ * Returns the WSDL part name.
+ *
+ * @return the part name, possibly empty.
+ */
public String getPartName() {
return partName;
}
+ /**
+ * Replaces the WSDL part name.
+ *
+ * @param partName new part name.
+ */
public void setPartName(String partName) {
this.partName = partName;
}
+ /**
+ * Returns the XML namespace for the parameter element.
+ *
+ * @return the target namespace, possibly empty.
+ */
public String getTargetNamespace() {
return targetNamespace;
}
+ /**
+ * Replaces the XML namespace for the parameter element.
+ *
+ * @param targetNamespace new target namespace.
+ */
public void setTargetNamespace(String targetNamespace) {
this.targetNamespace = targetNamespace;
}
+ /**
+ * Returns the parameter flow direction.
+ *
+ * @return the mode, never {@code null}.
+ */
public jakarta.jws.WebParam.Mode getMode() {
return mode;
}
+ /**
+ * Replaces the parameter flow direction.
+ *
+ * @param mode new mode.
+ */
public void setMode(jakarta.jws.WebParam.Mode mode) {
this.mode = mode;
}
+ /**
+ * Returns whether the parameter is in the SOAP header.
+ *
+ * @return {@code true} if the parameter is a header parameter.
+ */
public boolean isHeader() {
return header;
}
+ /**
+ * Sets whether the parameter is in the SOAP header.
+ *
+ * @param header {@code true} to place the parameter in the header.
+ */
public void setHeader(boolean header) {
this.header = header;
}
-
+
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapResult.java b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapResult.java
index 0022d39..84cecf8 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapResult.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapResult.java
@@ -16,43 +16,65 @@
package org.apache.cxf.endpoint.jaxws.definition;
/**
- * 注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。
- * https://www.cnblogs.com/zhao-shan/p/5515174.html
+ * Descriptor for the return value of a JAX-WS endpoint method that the
+ * generated builder will translate into a {@code @WebResult} annotation.
+ *
+ * @param the runtime type of the return value.
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.jws.WebResult
*/
public class SoapResult {
/**
- * 返回结果对象类型
+ * Runtime type of the return value; mandatory.
*/
private Class rtClass;
-
+
/**
- * 1、name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的
- * wsdl:part属性的名称。对于文档绑定,-name 参数是用于表示返回值的 XML 元素的局部名。对于 RPC 和 DOCUMENT/WRAPPED
- * 绑定,缺省值为 return。对于 DOCUMENT/BARE 绑定,缺省值为方法名 + Response。(字符串)
+ * WSDL name for the return value. For RPC and DOCUMENT/WRAPPED
+ * bindings, defaults to {@code "return"}.
*/
private String name = "";
/**
- * 2、targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE
- * 时才使用此参数。(字符串)
+ * XML namespace for the return value element. Only used for RPC or
+ * DOCUMENT/BARE operations.
*/
private String targetNamespace = "";
/**
- * 3、header:指定头中是否附带结果。缺省值为false。(布尔值)
+ * Whether the result is carried in the SOAP header. Defaults to
+ * {@code false}.
*/
private boolean header = false;
/**
- * 4、partName:指定 RPC 或 DOCUMENT/BARE 操作的结果的部件名称。缺省值为@WebResult.name。(字符串)
+ * WSDL part name for the result. Only used for RPC or
+ * DOCUMENT/BARE operations. Defaults to the {@code @WebResult}
+ * name value.
*/
private String partName = "";
-
+
+ /**
+ * Builds a result descriptor with the supplied type and name.
+ *
+ * @param rtClass runtime type of the return value.
+ * @param name the WSDL result name.
+ */
public SoapResult(Class rtClass, String name) {
this.rtClass = rtClass;
this.name = name;
}
-
+
+ /**
+ * Builds a fully specified result descriptor.
+ *
+ * @param rtClass runtime type of the return value.
+ * @param name the WSDL result name.
+ * @param targetNamespace XML namespace for the result element.
+ * @param header whether the result is in the SOAP header.
+ * @param partName the WSDL part name for the result.
+ */
public SoapResult(Class rtClass, String name, String targetNamespace, boolean header, String partName) {
this.rtClass = rtClass;
this.name = name;
@@ -61,42 +83,92 @@ public SoapResult(Class rtClass, String name, String targetNamespace, boolean
this.partName = partName;
}
+ /**
+ * Returns the runtime type of the return value.
+ *
+ * @return the return type.
+ */
public Class getRtClass() {
return rtClass;
}
+ /**
+ * Replaces the runtime type of the return value.
+ *
+ * @param rtClass new return type.
+ */
public void setRtClass(Class rtClass) {
this.rtClass = rtClass;
}
+ /**
+ * Returns the WSDL result name.
+ *
+ * @return the result name.
+ */
public String getName() {
return name;
}
+ /**
+ * Replaces the WSDL result name.
+ *
+ * @param name new result name.
+ */
public void setName(String name) {
this.name = name;
}
+ /**
+ * Returns the XML namespace for the result element.
+ *
+ * @return the target namespace, possibly empty.
+ */
public String getTargetNamespace() {
return targetNamespace;
}
+ /**
+ * Replaces the XML namespace for the result element.
+ *
+ * @param targetNamespace new target namespace.
+ */
public void setTargetNamespace(String targetNamespace) {
this.targetNamespace = targetNamespace;
}
+ /**
+ * Returns whether the result is in the SOAP header.
+ *
+ * @return {@code true} if the result is a header result.
+ */
public boolean isHeader() {
return header;
}
+ /**
+ * Sets whether the result is in the SOAP header.
+ *
+ * @param header {@code true} to place the result in the header.
+ */
public void setHeader(boolean header) {
this.header = header;
}
+ /**
+ * Returns the WSDL part name for the result.
+ *
+ * @return the part name, possibly empty.
+ */
public String getPartName() {
return partName;
}
+ /**
+ * Replaces the WSDL part name for the result.
+ *
+ * @param partName new part name.
+ */
public void setPartName(String partName) {
this.partName = partName;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapService.java b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapService.java
index fea21c2..9ce02aa 100644
--- a/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapService.java
+++ b/src/main/java/org/apache/cxf/endpoint/jaxws/definition/SoapService.java
@@ -15,52 +15,101 @@
*/
package org.apache.cxf.endpoint.jaxws.definition;
+/**
+ * Descriptor for the {@code @WebService} annotation attributes attached
+ * to a generated JAX-WS endpoint class.
+ *
+ * The descriptor bundles the mandatory {@linkplain #getName() name}
+ * and {@linkplain #getTargetNamespace() target namespace} together with
+ * optional {@linkplain #getServiceName() service name},
+ * {@linkplain #getPortName() port name},
+ * {@linkplain #getWsdlLocation() WSDL location} and
+ * {@linkplain #getEndpointInterface() endpoint interface}.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see jakarta.jws.WebService
+ */
public class SoapService {
/**
- * 此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType
- * 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
+ * WSDL port type name. Defaults to the simple class name.
*/
private final String name;
/**
- * 指定你想要的名称空间,默认是使用接口实现类的包名的反缀(字符串)
+ * XML namespace for the service. Defaults to the reversed package
+ * name of the implementation class.
*/
private final String targetNamespace;
/**
- * 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
+ * WSDL service name ({@code wsdl:service}). Defaults to the simple
+ * class name + {@code "Service"}.
*/
private String serviceName;
/**
- * wsdl:portName。缺省值为 WebService.name+Port。(字符串)
+ * WSDL port name ({@code wsdl:portName}). Defaults to
+ * {@code name + "Port"}.
*/
private String portName;
/**
- * 指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
+ * URL of the WSDL document. May be relative or absolute.
*/
private String wsdlLocation;
/**
- * 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口(字符串)
+ * Fully qualified name of the Service Endpoint Interface (SEI).
*/
private String endpointInterface;
+ /**
+ * Builds a descriptor with the mandatory name and target namespace.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ */
public SoapService(String name, String targetNamespace) {
this.name = name;
this.targetNamespace = targetNamespace;
}
-
+
+ /**
+ * Builds a descriptor with name, target namespace and service name.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ */
public SoapService(String name, String targetNamespace, String serviceName) {
this.name = name;
this.targetNamespace = targetNamespace;
this.serviceName = serviceName;
}
-
+
+ /**
+ * Builds a descriptor with name, target namespace, service name and
+ * port name.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @param portName the WSDL port name.
+ */
public SoapService(String name, String targetNamespace, String serviceName, String portName) {
this.name = name;
this.targetNamespace = targetNamespace;
this.serviceName = serviceName;
this.portName = portName;
}
-
+
+ /**
+ * Builds a descriptor with name, target namespace, service name,
+ * port name and WSDL location.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @param portName the WSDL port name.
+ * @param wsdlLocation URL of the WSDL document.
+ */
public SoapService(String name, String targetNamespace, String serviceName, String portName, String wsdlLocation) {
this.name = name;
this.targetNamespace = targetNamespace;
@@ -68,7 +117,17 @@ public SoapService(String name, String targetNamespace, String serviceName, Stri
this.portName = portName;
this.wsdlLocation = wsdlLocation;
}
-
+
+ /**
+ * Builds a fully specified descriptor with all attributes.
+ *
+ * @param name the WSDL port type name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param serviceName the WSDL service name.
+ * @param portName the WSDL port name.
+ * @param wsdlLocation URL of the WSDL document.
+ * @param endpointInterface fully qualified name of the SEI.
+ */
public SoapService(String name, String targetNamespace, String serviceName, String portName, String wsdlLocation,
String endpointInterface) {
this.name = name;
@@ -79,42 +138,92 @@ public SoapService(String name, String targetNamespace, String serviceName, Stri
this.endpointInterface = endpointInterface;
}
+ /**
+ * Returns the WSDL service name.
+ *
+ * @return the service name, possibly {@code null}.
+ */
public String getServiceName() {
return serviceName;
}
+ /**
+ * Replaces the WSDL service name.
+ *
+ * @param serviceName new service name.
+ */
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
+ /**
+ * Returns the WSDL port name.
+ *
+ * @return the port name, possibly {@code null}.
+ */
public String getPortName() {
return portName;
}
+ /**
+ * Replaces the WSDL port name.
+ *
+ * @param portName new port name.
+ */
public void setPortName(String portName) {
this.portName = portName;
}
+ /**
+ * Returns the URL of the WSDL document.
+ *
+ * @return the WSDL location, possibly {@code null}.
+ */
public String getWsdlLocation() {
return wsdlLocation;
}
+ /**
+ * Replaces the URL of the WSDL document.
+ *
+ * @param wsdlLocation new WSDL location.
+ */
public void setWsdlLocation(String wsdlLocation) {
this.wsdlLocation = wsdlLocation;
}
+ /**
+ * Returns the fully qualified name of the SEI.
+ *
+ * @return the endpoint interface, possibly {@code null}.
+ */
public String getEndpointInterface() {
return endpointInterface;
}
+ /**
+ * Replaces the fully qualified name of the SEI.
+ *
+ * @param endpointInterface new endpoint interface.
+ */
public void setEndpointInterface(String endpointInterface) {
this.endpointInterface = endpointInterface;
}
+ /**
+ * Returns the WSDL port type name.
+ *
+ * @return the name, never {@code null}.
+ */
public String getName() {
return name;
}
+ /**
+ * Returns the XML namespace for the service.
+ *
+ * @return the target namespace, never {@code null}.
+ */
public String getTargetNamespace() {
return targetNamespace;
}
diff --git a/src/main/java/org/apache/cxf/endpoint/utils/JaxrsEndpointApiUtils.java b/src/main/java/org/apache/cxf/endpoint/utils/JaxrsEndpointApiUtils.java
index 63be5ae..00db9bc 100644
--- a/src/main/java/org/apache/cxf/endpoint/utils/JaxrsEndpointApiUtils.java
+++ b/src/main/java/org/apache/cxf/endpoint/utils/JaxrsEndpointApiUtils.java
@@ -61,8 +61,28 @@
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;
+/**
+ * Utility methods used by the JAX-RS endpoint builders to create
+ * Javassist classes, interfaces, constructors, methods, and
+ * annotations.
+ *
+ * @author Loong Wan
+ * @since 3.0.0
+ * @see org.apache.cxf.endpoint.jaxrs.JaxrsEndpointApiCtClassBuilder
+ */
public class JaxrsEndpointApiUtils {
+ /**
+ * Creates or retrieves a concrete class in the supplied pool. If
+ * the class already exists the existing instance is returned.
+ *
+ * @param pool the class pool.
+ * @param classname fully qualified name of the class.
+ * @return the created or retrieved {@link CtClass}.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws CannotCompileException if the class cannot be compiled.
+ */
public static CtClass makeClass(final ClassPool pool, final String classname)
throws NotFoundException, CannotCompileException {
@@ -80,22 +100,50 @@ public static CtClass makeClass(final ClassPool pool, final String classname)
return declaring;
}
+ /**
+ * Creates a default no-argument constructor for the supplied class.
+ *
+ * @param declaring the class to add the constructor to.
+ * @return the created {@link CtConstructor}.
+ * @throws CannotCompileException if the constructor cannot be
+ * compiled.
+ */
public static CtConstructor defaultConstructor(final CtClass declaring) throws CannotCompileException {
- // 默认添加无参构造器
- CtConstructor cons = new CtConstructor(null, declaring);
- cons.setBody("{}");
+ CtConstructor cons = new CtConstructor(null, declaring);
+ cons.setBody("{}");
return cons;
}
-
- public static CtConstructor makeConstructor(final ClassPool pool, final CtClass declaring) throws NotFoundException, CannotCompileException {
- // 添加有参构造器,注入回调接口
+ /**
+ * Creates a constructor that accepts an {@link InvocationHandler}
+ * and delegates to {@code super(handler)}.
+ *
+ * @param pool the class pool.
+ * @param declaring the class to add the constructor to.
+ * @return the created {@link CtConstructor}.
+ * @throws NotFoundException if {@code InvocationHandler}
+ * cannot be resolved.
+ * @throws CannotCompileException if the constructor cannot be
+ * compiled.
+ */
+ public static CtConstructor makeConstructor(final ClassPool pool, final CtClass declaring) throws NotFoundException, CannotCompileException {
CtClass[] parameters = new CtClass[] {pool.get(InvocationHandler.class.getName())};
CtClass[] exceptions = new CtClass[] { pool.get("java.lang.Exception") };
return CtNewConstructor.make(parameters, exceptions, "{super($1);}", declaring);
-
}
+ /**
+ * Creates or retrieves an interface in the supplied pool. If the
+ * interface already exists the existing instance is returned.
+ *
+ * @param pool the class pool.
+ * @param classname fully qualified name of the interface.
+ * @return the created or retrieved {@link CtClass}.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws CannotCompileException if the interface cannot be
+ * compiled.
+ */
public static CtClass makeInterface(final ClassPool pool, final String classname)
throws NotFoundException, CannotCompileException {
@@ -112,45 +160,62 @@ public static CtClass makeInterface(final ClassPool pool, final String classname
}
+ /**
+ * Sets the superclass of the supplied class.
+ *
+ * @param pool the class pool.
+ * @param declaring the class whose superclass to set.
+ * @param clazz the Java class to use as superclass.
+ * @param the type of the superclass.
+ * @throws Exception if the superclass cannot be resolved or set.
+ */
public static void setSuperclass(final ClassPool pool, final CtClass declaring, final Class clazz)
throws Exception {
-
- /* 获得 JaxwsHandler 类作为动态类的父类 */
CtClass superclass = pool.get(clazz.getName());
declaring.setSuperclass(superclass);
-
}
-
+
+ /**
+ * Converts an array of {@link RestParam} descriptors into an array
+ * of {@link CtClass} parameter types.
+ *
+ * @param pool the class pool.
+ * @param params the parameter descriptors; may be {@code null} or
+ * empty.
+ * @return the resolved parameter types, or {@code null} when no
+ * parameters are supplied.
+ * @throws NotFoundException if a parameter type cannot be resolved.
+ */
public static CtClass[] makeParams(final ClassPool pool, RestParam>... params) throws NotFoundException {
- // 无参
if(params == null || params.length == 0) {
return null;
}
- // 方法参数
CtClass[] parameters = new CtClass[params.length];
for(int i = 0;i < params.length; i++) {
parameters[i] = pool.get(params[i].getType().getName());
}
-
return parameters;
}
- /**
- * 构造 @Path 注解
- * @param constPool {@link ConstPool} instance
- * @param path the path
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @Path} annotation.
+ *
+ * @param constPool the constant pool.
+ * @param path the URI template value.
+ * @return the constructed annotation.
+ */
public static Annotation annotPath(final ConstPool constPool, String path) {
return CtAnnotationBuilder.create(Path.class, constPool).addStringMember("value", path).build();
}
-
- /**
- * 构造 @Produces 注解
- * @param constPool {@link ConstPool} instance
- * @param mediaTypes the media types
- * @return {@link Annotation} instance
- */
+
+ /**
+ * Builds a {@code @Produces} annotation. When no media types are
+ * supplied the default {@code */*} value is used.
+ *
+ * @param constPool the constant pool.
+ * @param mediaTypes the produced media types.
+ * @return the constructed annotation.
+ */
public static Annotation annotProduces(final ConstPool constPool, String... mediaTypes) {
// 参数预处理
@@ -161,23 +226,20 @@ public static Annotation annotProduces(final ConstPool constPool, String... medi
}
- /**
- * 为方法添加 @HttpMethod、 @GET、 @POST、 @PUT、 @DELETE、 @PATCH、 @HEAD、 @OPTIONS、@Path、、@Consumes、@Produces、@RestBound、@RestParam 注解
- * @author [@Loong Wan](https://github.com/loong10k)
- * @param ctMethod {@link CtMethod} instance
- * @param constPool {@link ConstPool} instance
- * @param method {@link RestMethod} instance
- * @param bound {@link RestBound} instance
- * @param params the params
- * @see HttpMethod
- * @see GET
- * @see POST
- * @see PUT
- * @see DELETE
- * @see PATCH
- * @see HEAD
- * @see OPTIONS
- */
+ /**
+ * Attaches all JAX-RS method-level and parameter-level annotations
+ * to the supplied method: {@code @HttpMethod}, {@code @Path},
+ * {@code @Consumes}, {@code @Produces}, {@code @WebBound}, and
+ * parameter annotations ({@code @QueryParam}, {@code @PathParam},
+ * etc.).
+ *
+ * @param ctMethod the target method.
+ * @param constPool the constant pool.
+ * @param method the REST method descriptor.
+ * @param bound the binding descriptor, may be {@code null}.
+ * @param params the parameter descriptors; may be
+ * {@code null} or empty.
+ */
public static void methodAnnotations(final CtMethod ctMethod, final ConstPool constPool, final RestMethod method, final RestBound bound, RestParam>... params) {
// 添加方法注解
@@ -218,12 +280,14 @@ public static void methodAnnotations(final CtMethod ctMethod, final ConstPool co
}
- /**
- * 设置方法体
- * @param ctMethod {@link CtMethod} instance
- * @param method {@link RestMethod} instance
- * @throws CannotCompileException if can't compile
- */
+ /**
+ * Generates and sets the method body that dispatches calls through
+ * the configured {@link InvocationHandler}.
+ *
+ * @param ctMethod the target method.
+ * @param method the REST method descriptor.
+ * @throws CannotCompileException if the body cannot be compiled.
+ */
public static void methodBody(final CtMethod ctMethod, final RestMethod method) throws CannotCompileException {
// 构造方法体
@@ -240,27 +304,30 @@ public static void methodBody(final CtMethod ctMethod, final RestMethod method)
}
- /**
- * 设置方法异常捕获逻辑
- * @param pool {@link ClassPool} instance
- * @param ctMethod {@link CtMethod} instance
- * @throws NotFoundException if not found
- * @throws CannotCompileException if can't compile
- */
+ /**
+ * Adds a catch block that prints and re-throws any
+ * {@code Exception} thrown by the method body.
+ *
+ * @param pool the class pool.
+ * @param ctMethod the target method.
+ * @throws NotFoundException if {@code Exception} cannot be
+ * resolved.
+ * @throws CannotCompileException if the catch block cannot be
+ * compiled.
+ */
public static void methodCatch(final ClassPool pool, final CtMethod ctMethod) throws NotFoundException, CannotCompileException {
-
- // 构造异常处理逻辑
CtClass etype = pool.get("java.lang.Exception");
ctMethod.addCatch("{ System.out.println($e); throw $e; }", etype);
-
}
-
- /**
- * 构造 @WebBound 注解
- * @param constPool {@link ConstPool} instance
- * @param bound {@link RestBound} instance
- * @return {@link Annotation} instance
- */
+
+ /**
+ * Builds a {@code @WebBound} annotation from a JAX-RS bound
+ * descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param bound the bound descriptor.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebBound(final ConstPool constPool, final RestBound bound) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(WebBound.class, constPool).
@@ -272,12 +339,16 @@ public static Annotation annotWebBound(final ConstPool constPool, final RestBoun
}
- /**
- * 根据参数 构造 @GET、 @POST、 @PUT、 @DELETE、 @PATCH、 @HEAD、 @OPTIONS 注解
- * @param constPool {@link ConstPool} instance
- * @param method {@link RestMethod} instance
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds the appropriate HTTP method annotation ({@code @GET},
+ * {@code @POST}, {@code @PUT}, {@code @DELETE}, {@code @PATCH},
+ * {@code @HEAD}, {@code @OPTIONS}) based on the verb carried by
+ * the descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param method the REST method descriptor.
+ * @return the constructed annotation.
+ */
public static Annotation annotHttpMethod(final ConstPool constPool, final RestMethod method) {
Annotation annot = null;
@@ -311,12 +382,14 @@ public static Annotation annotHttpMethod(final ConstPool constPool, final RestMe
return annot;
}
- /**
- * 构造 @Consumes 注解
- * @param constPool {@link ConstPool} instance
- * @param consumes the consumes
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @Consumes} annotation. When no media types are
+ * supplied the default {@code */*} value is used.
+ *
+ * @param constPool the constant pool.
+ * @param consumes the consumed media types.
+ * @return the constructed annotation.
+ */
public static Annotation annotConsumes(final ConstPool constPool, String... consumes) {
// 参数预处理
consumes = ArrayUtils.isEmpty(consumes) ? new String[] {"*/*"} : consumes;
@@ -325,12 +398,19 @@ public static Annotation annotConsumes(final ConstPool constPool, String... cons
return builder.build();
}
- /**
- * 构造 @BeanParam 、@CookieParam、@FormParam、@HeaderParam、@MatrixParam、@PathParam、@QueryParam 参数注解
- * @param constPool {@link ConstPool} instance
- * @param params the params
- * @return {@link Annotation} Array
- */
+ /**
+ * Builds parameter-level annotations for each {@link RestParam}
+ * descriptor. The annotation type is determined by the parameter's
+ * {@link HttpParamEnum} binding source. When a default value is
+ * configured, a {@code @DefaultValue} annotation is appended.
+ *
+ * @param constPool the constant pool.
+ * @param params the parameter descriptors; may be {@code null}
+ * or empty.
+ * @return a two-dimensional annotation array suitable for
+ * {@link ParameterAnnotationsAttribute#setAnnotations(Annotation[][])},
+ * or {@code null} when no parameters are supplied.
+ */
public static Annotation[][] annotParams(final ConstPool constPool, RestParam>... params) {
// 添加 @WebParam 参数注解
@@ -379,7 +459,7 @@ public static Annotation[][] annotParams(final ConstPool constPool, RestParam>
Annotation defAnnot = new Annotation(DefaultValue.class.getName(), constPool);
defAnnot.addMemberValue("value", new StringMemberValue(params[i].getDef(), constPool));
- paramArrays[i][1] = paramAnnot;
+ paramArrays[i][1] = defAnnot;
} else {
paramArrays[i][0] = paramAnnot;
diff --git a/src/main/java/org/apache/cxf/endpoint/utils/JaxwsEndpointApiUtils.java b/src/main/java/org/apache/cxf/endpoint/utils/JaxwsEndpointApiUtils.java
index 18d0ac2..b53fe48 100644
--- a/src/main/java/org/apache/cxf/endpoint/utils/JaxwsEndpointApiUtils.java
+++ b/src/main/java/org/apache/cxf/endpoint/utils/JaxwsEndpointApiUtils.java
@@ -53,10 +53,30 @@
import javassist.bytecode.ParameterAnnotationsAttribute;
import javassist.bytecode.annotation.Annotation;
+/**
+ * Utility methods used by the JAX-WS endpoint builders to create
+ * Javassist classes, interfaces, constructors, methods, and
+ * annotations.
+ *
+ * @author [@Loong Wan](https://github.com/loong10k)
+ * @since 3.0.0
+ * @see org.apache.cxf.endpoint.jaxws.JaxwsEndpointApiCtClassBuilder
+ */
public class JaxwsEndpointApiUtils {
-
+
protected static final Logger LOG = LoggerFactory.getLogger(JaxwsEndpointApiUtils.class);
+ /**
+ * Creates or retrieves a concrete class in the supplied pool. If
+ * the class already exists the existing instance is returned.
+ *
+ * @param pool the class pool.
+ * @param classname fully qualified name of the class.
+ * @return the created or retrieved {@link CtClass}.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws CannotCompileException if the class cannot be compiled.
+ */
public static CtClass makeClass(final ClassPool pool, final String classname)
throws NotFoundException, CannotCompileException {
@@ -72,22 +92,50 @@ public static CtClass makeClass(final ClassPool pool, final String classname)
return declaring;
}
+ /**
+ * Creates a default no-argument constructor for the supplied class.
+ *
+ * @param declaring the class to add the constructor to.
+ * @return the created {@link CtConstructor}.
+ * @throws CannotCompileException if the constructor cannot be
+ * compiled.
+ */
public static CtConstructor defaultConstructor(final CtClass declaring) throws CannotCompileException {
- // 默认添加无参构造器
- CtConstructor cons = new CtConstructor(null, declaring);
- cons.setBody("{}");
+ CtConstructor cons = new CtConstructor(null, declaring);
+ cons.setBody("{}");
return cons;
}
-
- public static CtConstructor makeConstructor(final ClassPool pool, final CtClass declaring) throws NotFoundException, CannotCompileException {
- // 添加有参构造器,注入回调接口
+ /**
+ * Creates a constructor that accepts an {@link InvocationHandler}
+ * and delegates to {@code super(handler)}.
+ *
+ * @param pool the class pool.
+ * @param declaring the class to add the constructor to.
+ * @return the created {@link CtConstructor}.
+ * @throws NotFoundException if {@code InvocationHandler}
+ * cannot be resolved.
+ * @throws CannotCompileException if the constructor cannot be
+ * compiled.
+ */
+ public static CtConstructor makeConstructor(final ClassPool pool, final CtClass declaring) throws NotFoundException, CannotCompileException {
CtClass[] parameters = new CtClass[] {pool.get(InvocationHandler.class.getName())};
CtClass[] exceptions = new CtClass[] { pool.get("java.lang.Exception") };
return CtNewConstructor.make(parameters, exceptions, "{super($1);}", declaring);
-
}
+ /**
+ * Creates or retrieves an interface in the supplied pool. If the
+ * interface already exists the existing instance is returned.
+ *
+ * @param pool the class pool.
+ * @param classname fully qualified name of the interface.
+ * @return the created or retrieved {@link CtClass}.
+ * @throws NotFoundException if a referenced type cannot be
+ * resolved.
+ * @throws CannotCompileException if the interface cannot be
+ * compiled.
+ */
public static CtClass makeInterface(final ClassPool pool, final String classname)
throws NotFoundException, CannotCompileException {
@@ -104,39 +152,54 @@ public static CtClass makeInterface(final ClassPool pool, final String classname
}
+ /**
+ * Sets the superclass of the supplied class.
+ *
+ * @param pool the class pool.
+ * @param declaring the class whose superclass to set.
+ * @param clazz the Java class to use as superclass.
+ * @param the type of the superclass.
+ * @throws Exception if the superclass cannot be resolved or set.
+ */
public static void setSuperclass(final ClassPool pool, final CtClass declaring, final Class clazz)
throws Exception {
-
- /* 获得 JaxwsHandler 类作为动态类的父类 */
CtClass superclass = pool.get(clazz.getName());
declaring.setSuperclass(superclass);
-
}
+ /**
+ * Converts an array of {@link SoapParam} descriptors into an array
+ * of {@link CtClass} parameter types.
+ *
+ * @param pool the class pool.
+ * @param params the parameter descriptors; may be {@code null} or
+ * empty.
+ * @return the resolved parameter types, or {@code null} when no
+ * parameters are supplied.
+ * @throws NotFoundException if a parameter type cannot be resolved.
+ */
public static CtClass[] makeParams(final ClassPool pool, SoapParam>... params) throws NotFoundException {
- // 无参
if(params == null || params.length == 0) {
return null;
}
- // 方法参数
CtClass[] parameters = new CtClass[params.length];
for(int i = 0;i < params.length; i++) {
parameters[i] = pool.get(params[i].getType().getName());
}
-
return parameters;
}
- /**
- * 构造 @WebServiceProvider 注解
- * @param constPool : {@link ConstPool} instance
- * @param wsdlLocation :Location of the WSDL description for the service.
- * @param serviceName :Service name.
- * @param targetNamespace :Target namespace for the service
- * @param portName :Port name.
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @WebServiceProvider} annotation.
+ *
+ * @param constPool the constant pool.
+ * @param wsdlLocation URL of the WSDL document.
+ * @param serviceName the WSDL service name.
+ * @param targetNamespace the XML namespace for the service.
+ * @param portName the WSDL port name.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebServiceProvider(final ConstPool constPool, String wsdlLocation,
String serviceName, String targetNamespace, String portName) {
@@ -151,12 +214,14 @@ public static Annotation annotWebServiceProvider(final ConstPool constPool, Stri
}
- /**
- * 构造 @WebService 注解
- * @param constPool : {@link ConstPool} instance
- * @param service : {@link SoapService} instance
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @WebService} annotation from a SOAP service
+ * descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param service the service descriptor.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebService(final ConstPool constPool, final SoapService service) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(WebService.class, constPool)
@@ -180,14 +245,15 @@ public static Annotation annotWebService(final ConstPool constPool, final SoapSe
}
- /**
- * 构造 @Addressing 注解
- * @param constPool : {@link ConstPool} instance
- * @param enabled : the value of enabled
- * @param required : the value of required
- * @param responses : {@link Responses} instance
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds an {@code @Addressing} annotation.
+ *
+ * @param constPool the constant pool.
+ * @param enabled whether WS-Addressing is enabled.
+ * @param required whether WS-Addressing is required.
+ * @param responses the addressing responses policy.
+ * @return the constructed annotation.
+ */
public static Annotation annotAddressing(final ConstPool constPool, final boolean enabled, final boolean required,
final Responses responses) {
@@ -198,23 +264,27 @@ public static Annotation annotAddressing(final ConstPool constPool, final boolea
}
- /**
- * 构造 @ServiceMode 注解
- * @param constPool : {@link ConstPool} instance
- * @param mode : the mode of {@link Service}
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @ServiceMode} annotation.
+ *
+ * @param constPool the constant pool.
+ * @param mode the service mode ({@code PAYLOAD} or
+ * {@code MESSAGE}).
+ * @return the constructed annotation.
+ */
public static Annotation annotServiceMode(final ConstPool constPool, final Service.Mode mode) {
return CtAnnotationBuilder.create(ServiceMode.class, constPool).addEnumMember("value", mode).build();
}
- /**
- * 构造 @HandlerChain 注解
- * @param constPool : {@link ConstPool} instance
- * @param name : the value of name
- * @param file : the value of file
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @HandlerChain} annotation.
+ *
+ * @param constPool the constant pool.
+ * @param name the handler chain name; may be {@code null}.
+ * @param file the handler chain file path; may be
+ * {@code null}.
+ * @return the constructed annotation.
+ */
public static Annotation annotHandlerChain(final ConstPool constPool, String name, String file) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(HandlerChain.class, constPool);
@@ -229,18 +299,20 @@ public static Annotation annotHandlerChain(final ConstPool constPool, String nam
}
- /**
- *
- * 为方法添加 @WebMethod、 @WebResult、@WebBound、@WebParam 注解
- * @author [@Loong Wan](https://github.com/loong10k)
- * @param ctMethod : {@link CtMethod} instance
- * @param constPool : {@link ConstPool} instance
- * @param result : {@link SoapResult} instance
- * @param method : {@link SoapMethod} instance
- * @param bound : {@link SoapBound} instance
- * @param : 泛型参数
- * @param params : The {@link SoapParam} params
- */
+ /**
+ * Attaches all JAX-WS method-level and parameter-level annotations
+ * to the supplied method: {@code @WebMethod}, {@code @WebResult},
+ * {@code @WebBound}, and {@code @WebParam}.
+ *
+ * @param ctMethod the target method.
+ * @param constPool the constant pool.
+ * @param result the result descriptor, may be {@code null}.
+ * @param method the SOAP method descriptor.
+ * @param bound the binding descriptor, may be {@code null}.
+ * @param params the parameter descriptors; may be
+ * {@code null} or empty.
+ * @param the return type parameter.
+ */
public static void methodAnnotations(final CtMethod ctMethod, final ConstPool constPool, final SoapResult result, final SoapMethod method, final SoapBound bound, SoapParam>... params) {
// 添加方法注解
@@ -273,12 +345,14 @@ public static void methodAnnotations(final CtMethod ctMethod, final ConstPoo
}
- /**
- * 设置方法体
- * @param ctMethod : {@link CtMethod} instance
- * @param method : {@link SoapMethod} instance
- * @throws CannotCompileException if can't compile
- */
+ /**
+ * Generates and sets the method body that dispatches calls through
+ * the configured {@link InvocationHandler}.
+ *
+ * @param ctMethod the target method.
+ * @param method the SOAP method descriptor.
+ * @throws CannotCompileException if the body cannot be compiled.
+ */
public static void methodBody(final CtMethod ctMethod, final SoapMethod method) throws CannotCompileException {
// 构造方法体
@@ -295,13 +369,17 @@ public static void methodBody(final CtMethod ctMethod, final SoapMethod method)
}
- /**
- * 设置方法异常捕获逻辑
- * @param pool : {@link ClassPool} instance
- * @param ctMethod : {@link CtMethod} instance
- * @throws NotFoundException if not found
- * @throws CannotCompileException if can't compile
- */
+ /**
+ * Adds a catch block that prints and re-throws any
+ * {@code Exception} thrown by the method body.
+ *
+ * @param pool the class pool.
+ * @param ctMethod the target method.
+ * @throws NotFoundException if {@code Exception} cannot be
+ * resolved.
+ * @throws CannotCompileException if the catch block cannot be
+ * compiled.
+ */
public static void methodCatch(final ClassPool pool, final CtMethod ctMethod) throws NotFoundException, CannotCompileException {
// 构造异常处理逻辑
@@ -310,12 +388,14 @@ public static void methodCatch(final ClassPool pool, final CtMethod ctMethod) th
}
- /**
- * 构造 @WebBound 注解
- * @param constPool : {@link ConstPool} instance
- * @param bound : {@link SoapBound} instance
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @WebBound} annotation from a JAX-WS bound
+ * descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param bound the bound descriptor.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebBound(final ConstPool constPool, final SoapBound bound) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(WebBound.class, constPool).
@@ -327,12 +407,14 @@ public static Annotation annotWebBound(final ConstPool constPool, final SoapBoun
}
- /**
- * 构造 @WebMethod 注解
- * @param constPool : {@link ConstPool} instance
- * @param method : {@link SoapMethod} instance
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @WebMethod} annotation from a SOAP method
+ * descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param method the SOAP method descriptor.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebMethod(final ConstPool constPool, final SoapMethod method) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(WebMethod.class, constPool)
@@ -345,12 +427,17 @@ public static Annotation annotWebMethod(final ConstPool constPool, final SoapMet
}
- /**
- * 构造 @WebParam 参数注解
- * @param constPool : {@link ConstPool} instance
- * @param params : The {@link SoapParam} params
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds {@code @WebParam} parameter-level annotations for each
+ * {@link SoapParam} descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param params the parameter descriptors; may be {@code null}
+ * or empty.
+ * @return a two-dimensional annotation array suitable for
+ * {@link ParameterAnnotationsAttribute#setAnnotations(Annotation[][])},
+ * or {@code null} when no parameters are supplied.
+ */
public static Annotation[][] annotParams(final ConstPool constPool, SoapParam>... params) {
// 添加 @WebParam 参数注解
@@ -396,13 +483,15 @@ public static Annotation[][] annotParams(final ConstPool constPool, SoapParam>
return null;
}
- /**
- * 构造 @WebResult 注解
- * @param constPool : {@link ConstPool} instance
- * @param result : {@link SoapResult} instance
- * @param : 泛型参数
- * @return {@link Annotation} instance
- */
+ /**
+ * Builds a {@code @WebResult} annotation from a SOAP result
+ * descriptor.
+ *
+ * @param constPool the constant pool.
+ * @param result the result descriptor.
+ * @param the return type parameter.
+ * @return the constructed annotation.
+ */
public static Annotation annotWebResult(final ConstPool constPool, final SoapResult result) {
CtAnnotationBuilder builder = CtAnnotationBuilder.create(WebResult.class, constPool)
@@ -419,6 +508,11 @@ public static Annotation annotWebResult(final ConstPool constPool, final Soa
}
+ /**
+ * Placeholder for future cleanup logic.
+ *
+ * @param declaring the class to clean up.
+ */
public static void rm(CtClass declaring) {
}
diff --git a/src/test/java/org/apache/cxf/endpoint/EndpointApiTest.java b/src/test/java/org/apache/cxf/endpoint/EndpointApiTest.java
new file mode 100644
index 0000000..f0e0fa5
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/EndpointApiTest.java
@@ -0,0 +1,36 @@
+package org.apache.cxf.endpoint;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+public class EndpointApiTest {
+
+ @Test
+ public void shouldCreateInstanceWithDefaultConstructor() {
+ EndpointApi api = new EndpointApi() {};
+ assertNull(api.getHandler());
+ }
+
+ @Test
+ public void shouldStoreHandlerViaConstructor() {
+ InvocationHandler handler = (proxy, method, args) -> null;
+ EndpointApi api = new EndpointApi(handler) {};
+ assertSame(handler, api.getHandler());
+ }
+
+ @Test
+ public void shouldReturnNullHandlerWhenDefaultConstructed() {
+ EndpointApi api = new EndpointApi() {};
+ assertNull(api.getHandler());
+ }
+
+ @Test
+ public void shouldAcceptNullHandler() {
+ EndpointApi api = new EndpointApi(null) {};
+ assertNull(api.getHandler());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/annotation/WebBoundTest.java b/src/test/java/org/apache/cxf/endpoint/annotation/WebBoundTest.java
new file mode 100644
index 0000000..4cbf759
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/annotation/WebBoundTest.java
@@ -0,0 +1,32 @@
+package org.apache.cxf.endpoint.annotation;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class WebBoundTest {
+
+ @Test
+ public void shouldHaveCorrectDefaults() throws Exception {
+ WebBound bound = WebBoundTestHelper.class.getAnnotation(WebBound.class);
+ assertNotNull(bound);
+ assertEquals("", bound.uid());
+ assertEquals("{}", bound.json());
+ }
+
+ @Test
+ public void shouldHaveCustomValues() throws Exception {
+ WebBound bound = WebBoundCustomHelper.class.getAnnotation(WebBound.class);
+ assertNotNull(bound);
+ assertEquals("uid-123", bound.uid());
+ assertEquals("{\"key\":\"val\"}", bound.json());
+ }
+
+ @WebBound
+ static class WebBoundTestHelper {
+ }
+
+ @WebBound(uid = "uid-123", json = "{\"key\":\"val\"}")
+ static class WebBoundCustomHelper {
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/annotation/WebEndpointTest.java b/src/test/java/org/apache/cxf/endpoint/annotation/WebEndpointTest.java
new file mode 100644
index 0000000..22ffaff
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/annotation/WebEndpointTest.java
@@ -0,0 +1,25 @@
+package org.apache.cxf.endpoint.annotation;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class WebEndpointTest {
+
+ @Test
+ public void shouldHaveCorrectDefaults() throws Exception {
+ WebEndpoint ep = WebEndpointHelper.class.getAnnotation(WebEndpoint.class);
+ assertNotNull(ep);
+ assertEquals("http://localhost:8080", ep.addr());
+ assertArrayEquals(new String[]{""}, ep.inInterceptors());
+ assertArrayEquals(new String[]{""}, ep.outInterceptors());
+ assertArrayEquals(new String[]{""}, ep.inFaults());
+ assertArrayEquals(new String[]{""}, ep.outFaults());
+ assertArrayEquals(new String[]{""}, ep.features());
+ assertArrayEquals(new String[]{""}, ep.handlers());
+ }
+
+ @WebEndpoint(addr = "http://localhost:8080")
+ static class WebEndpointHelper {
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsApiCtClassBuilder_Test.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsApiCtClassBuilder_Test.java
index fcbdcab..779dacc 100644
--- a/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsApiCtClassBuilder_Test.java
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsApiCtClassBuilder_Test.java
@@ -8,6 +8,8 @@
import java.lang.reflect.Method;
import java.util.UUID;
+import static org.junit.Assert.*;
+
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.endpoint.jaxrs.definition.HttpMethodEnum;
@@ -79,49 +81,23 @@ public void testClass() throws Exception {
@Test
public void testInstance() throws Exception{
-
+
InvocationHandler handler = new EndpointApiInvocationHandler();
-
- Object ctObject = new JaxrsEndpointApiCtClassBuilder("org.apache.cxf.spring.boot.FirstCaseV2")
+
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.apache.cxf.spring.boot.FirstCaseV2")
.path("getxx")
.makeField("public int k = 3;")
.newField(String.class, "uid", UUID.randomUUID().toString())
.newMethod(String.class, HttpMethodEnum.GET, "sayHello", "{id}/info" , new RestBound("ID01201"),new RestParam(String.class, "id", HttpParamEnum.PATH))
.newMethod(HttpMethodEnum.GET, "sayHello2", "{id}/info", new RestBound("ID01201") ,new RestParam(String.class, "text"))
- .toInstance(handler);
-
- Class clazz = ctObject.getClass();
-
- System.err.println("=========Type Annotations======================");
- for (Annotation element : clazz.getAnnotations()) {
- System.out.println(element.toString());
- }
-
- System.err.println("=========Fields======================");
- for (Field element : clazz.getDeclaredFields()) {
- System.out.println(element.getName());
- for (Annotation anno : element.getAnnotations()) {
- System.out.println(anno.toString());
- }
- }
- System.err.println("=========Methods======================");
- for (Method method : clazz.getDeclaredMethods()) {
- System.out.println(method.getName());
- System.err.println("=========Method Annotations======================");
- for (Annotation anno : method.getAnnotations()) {
- System.out.println(anno.toString());
- }
- System.err.println("=========Method Parameter Annotations======================");
- for (Annotation[] anno : method.getParameterAnnotations()) {
- System.out.println(anno[0].toString());
- }
- }
- System.err.println("=========sayHello======================");
- Method sayHello = clazz.getMethod("sayHello", String.class);
- sayHello.invoke(ctObject, " hi Hello " );
- System.err.println("=========sayHello2======================");
- Method sayHello2 = clazz.getMethod("sayHello2", String.class);
- sayHello2.invoke(ctObject, " hi Hello2 " );
+ .build();
+
+ assertNotNull(ctClass);
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ assertNotNull(ctClass.getDeclaredMethod("sayHello2"));
+ assertNotNull(ctClass.getDeclaredField("k"));
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
}
}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilderTest.java
new file mode 100644
index 0000000..62a55b2
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiCtClassBuilderTest.java
@@ -0,0 +1,276 @@
+package org.apache.cxf.endpoint.jaxrs;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.InvocationHandler;
+
+import org.apache.cxf.endpoint.jaxrs.definition.HttpMethodEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.HttpParamEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.RestBound;
+import org.apache.cxf.endpoint.jaxrs.definition.RestMethod;
+import org.apache.cxf.endpoint.jaxrs.definition.RestParam;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxrsEndpointApiCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildClassWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsDefault1")
+ .build();
+ assertNotNull(ctClass);
+ assertEquals("org.test.JaxrsDefault1", ctClass.getName());
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildClassWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder(pool, "org.test.JaxrsCustom1")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddPathAnnotation() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsPath1")
+ .path("/api")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Path.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddProducesAnnotation() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsProd1")
+ .produces("application/json")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Produces.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddDefaultProducesWhenEmpty() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsProd2")
+ .produces()
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Produces.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindWithUidAndJson() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsBind1")
+ .bind("uid-1", "{}")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindWithRestBound() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsBind2")
+ .bind(new RestBound("uid-2", "{\"x\":1}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldMakeFieldFromSource() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsField1")
+ .makeField("public int k = 3;")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("k"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddTypedField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsField2")
+ .newField(String.class, "uid", "test-value")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsField3")
+ .makeField("public int k = 3;")
+ .removeField("k")
+ .build();
+ try {
+ ctClass.getDeclaredField("k");
+ fail("Field should have been removed");
+ } catch (javassist.NotFoundException e) {
+ // expected
+ }
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsField4")
+ .removeField("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithReturnTypeAndBound() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod1")
+ .newMethod(String.class, HttpMethodEnum.GET, "sayHello", "/{id}",
+ new RestBound("b1"), new RestParam(String.class, "id", HttpParamEnum.PATH))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithoutReturnType() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod2")
+ .newMethod(HttpMethodEnum.POST, "create", "/",
+ new RestParam(String.class, "name"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("create"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithRestMethodAndBound() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.GET, "findById", "/{id}");
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod3")
+ .newMethod(String.class, rm, new RestBound("b1"),
+ new RestParam(String.class, "id", HttpParamEnum.PATH))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("findById"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithRestMethodNoBound() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.GET, "list", "/");
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod4")
+ .newMethod(String.class, rm)
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("list"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithHttpMethodEnumNamePath() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod5")
+ .newMethod(HttpMethodEnum.PUT, "update", "/{id}",
+ new RestBound("b1"), new RestParam(String.class, "id"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("update"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithRestMethodBoundNoReturn() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.DELETE, "remove", "/{id}");
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod6")
+ .newMethod(rm, new RestBound("b1"),
+ new RestParam(String.class, "id"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("remove"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithRestMethodNoBoundNoReturn() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.GET, "health", "/health");
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod7")
+ .newMethod(rm)
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("health"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingMethod() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod8")
+ .newMethod(HttpMethodEnum.GET, "temp", "/temp")
+ .removeMethod("temp")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethod() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod9")
+ .removeMethod("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod10")
+ .newMethod(String.class, HttpMethodEnum.GET, "withParam", "/p",
+ new RestParam(String.class, "x"))
+ .removeMethod("withParam", new RestParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod11")
+ .removeMethod("nope", new RestParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddVoidMethodWithNoParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsMethod12")
+ .newMethod(HttpMethodEnum.GET, "noop", "/noop")
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("noop"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSetSuperclassToEndpointApi() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsParent1")
+ .build();
+ assertNotNull(ctClass.getSuperclass());
+ assertEquals("org.apache.cxf.endpoint.EndpointApi", ctClass.getSuperclass().getName());
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldHaveDefaultConstructor() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsCtor1")
+ .build();
+ assertTrue(ctClass.getConstructors().length > 0);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxrsEndpointApiCtClassBuilder builder = new JaxrsEndpointApiCtClassBuilder("org.test.JaxrsChain1");
+ JaxrsEndpointApiCtClassBuilder result = builder
+ .path("/api")
+ .produces("application/json")
+ .bind("uid", "{}")
+ .makeField("public int k = 3;")
+ .newField(String.class, "name", "test")
+ .newMethod(HttpMethodEnum.GET, "get", "/get");
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilderTest.java
new file mode 100644
index 0000000..6e80691
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiImplCtClassBuilderTest.java
@@ -0,0 +1,109 @@
+package org.apache.cxf.endpoint.jaxrs;
+
+import static org.junit.Assert.*;
+
+import org.apache.cxf.endpoint.jaxrs.definition.HttpMethodEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.HttpParamEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.RestBound;
+import org.apache.cxf.endpoint.jaxrs.definition.RestParam;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxrsEndpointApiImplCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildImplClassWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl1")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildImplClassWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder(pool, "org.test.JaxrsImpl2")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardPathToInterface() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl3")
+ .path("/api")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardProducesToInterface() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl4")
+ .produces("application/json")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardDefaultProducesToInterface() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl5")
+ .produces()
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardBindUidJson() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl6")
+ .bind("uid", "{}")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardBindRestBound() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl7")
+ .bind(new RestBound("uid", "{}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodToBothInterfaceAndImpl() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImpl8")
+ .path("/api")
+ .newMethod(String.class, HttpMethodEnum.GET, "hello", "/hello",
+ new RestBound("b1"), new RestParam(String.class, "name"))
+ .build();
+ assertNotNull(ctClass);
+ assertNotNull(ctClass.getDeclaredMethod("hello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldUseImplSuffix() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImplSuffix1")
+ .build();
+ assertTrue(ctClass.getName().endsWith("$Impl"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxrsEndpointApiImplCtClassBuilder builder = new JaxrsEndpointApiImplCtClassBuilder("org.test.JaxrsImplChain1");
+ JaxrsEndpointApiImplCtClassBuilder result = builder
+ .path("/api")
+ .produces("application/json");
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilderTest.java
new file mode 100644
index 0000000..730c998
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/JaxrsEndpointApiInterfaceCtClassBuilderTest.java
@@ -0,0 +1,272 @@
+package org.apache.cxf.endpoint.jaxrs;
+
+import static org.junit.Assert.*;
+
+import org.apache.cxf.endpoint.jaxrs.definition.HttpMethodEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.HttpParamEnum;
+import org.apache.cxf.endpoint.jaxrs.definition.RestBound;
+import org.apache.cxf.endpoint.jaxrs.definition.RestMethod;
+import org.apache.cxf.endpoint.jaxrs.definition.RestParam;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxrsEndpointApiInterfaceCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildInterfaceWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface1")
+ .build();
+ assertNotNull(ctClass);
+ assertTrue(ctClass.isInterface());
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildInterfaceWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder(pool, "org.test.JaxrsIface2")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddPathAnnotation() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface3")
+ .path("/api")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Path.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddProducesAnnotation() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface4")
+ .produces("application/xml")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Produces.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddDefaultProduces() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface5")
+ .produces()
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.ws.rs.Produces.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindUidJson() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface6")
+ .bind("uid", "{}")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindRestBound() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface7")
+ .bind(new RestBound("uid", "{}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldMakeFieldFromSource() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface8")
+ .makeField("public int k = 3;")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("k"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddTypedField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface9")
+ .newField(String.class, "uid", "test")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenFieldAlreadyExists() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface10")
+ .newField(String.class, "uid", "test")
+ .newField(String.class, "uid", "test2")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface11")
+ .makeField("public int k = 3;")
+ .removeField("k")
+ .build();
+ try {
+ ctClass.getDeclaredField("k");
+ fail("Field should have been removed");
+ } catch (javassist.NotFoundException e) {
+ // expected
+ }
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentField() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface12")
+ .removeField("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithAllParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface13")
+ .abstractMethod(String.class, HttpMethodEnum.GET, "find", "/{id}",
+ new RestBound("b1"), new RestParam(String.class, "id", HttpParamEnum.PATH))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("find"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithoutBound() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface14")
+ .abstractMethod(String.class, HttpMethodEnum.GET, "find", "/{id}",
+ new RestParam(String.class, "id"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("find"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithRestMethodAndBound() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.POST, "create", "/");
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface15")
+ .abstractMethod(String.class, rm, new RestBound("b1"),
+ new RestParam(String.class, "data"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("create"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithRestMethodNoBound() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.GET, "list", "/");
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface16")
+ .abstractMethod(String.class, rm, new RestParam(String.class, "q"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("list"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodNoReturnNoBoundHttpEnum() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface17")
+ .abstractMethod(HttpMethodEnum.GET, "health", "/health")
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("health"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodNoReturnWithBoundHttpEnum() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface18")
+ .abstractMethod(HttpMethodEnum.POST, "save", "/", new RestBound("b1"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("save"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodNoReturnWithBoundRestMethod() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.DELETE, "delete", "/{id}");
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface19")
+ .abstractMethod(rm, new RestBound("b1"), new RestParam(String.class, "id"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("delete"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodNoReturnNoBoundRestMethod() throws Exception {
+ RestMethod rm = new RestMethod(HttpMethodEnum.GET, "ping", "/ping");
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface20")
+ .abstractMethod(rm)
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("ping"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingMethod() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface21")
+ .abstractMethod(HttpMethodEnum.GET, "temp", "/temp")
+ .removeMethod("temp")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethod() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface22")
+ .removeMethod("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface23")
+ .abstractMethod(String.class, HttpMethodEnum.GET, "withParam", "/p",
+ new RestParam(String.class, "x"))
+ .removeMethod("withParam", new RestParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface24")
+ .removeMethod("nope", new RestParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxrsEndpointApiInterfaceCtClassBuilder builder = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface25");
+ JaxrsEndpointApiInterfaceCtClassBuilder result = builder
+ .path("/api")
+ .produces("application/json")
+ .bind("uid", "{}")
+ .abstractMethod(org.apache.cxf.endpoint.jaxrs.definition.HttpMethodEnum.GET, "get", "/get");
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddVoidAbstractMethodWithNoParams() throws Exception {
+ CtClass ctClass = new JaxrsEndpointApiInterfaceCtClassBuilder("org.test.JaxrsIface26")
+ .abstractMethod(HttpMethodEnum.GET, "noop", "/noop")
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("noop"));
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnumTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnumTest.java
new file mode 100644
index 0000000..1a4edcf
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpMethodEnumTest.java
@@ -0,0 +1,42 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import java.util.NoSuchElementException;
+
+import org.junit.Test;
+
+public class HttpMethodEnumTest {
+
+ @Test
+ public void shouldReturnCorrectKeyForEachVerb() {
+ assertEquals("GET", HttpMethodEnum.GET.getKey());
+ assertEquals("POST", HttpMethodEnum.POST.getKey());
+ assertEquals("PUT", HttpMethodEnum.PUT.getKey());
+ assertEquals("DELETE", HttpMethodEnum.DELETE.getKey());
+ assertEquals("PATCH", HttpMethodEnum.PATCH.getKey());
+ assertEquals("HEAD", HttpMethodEnum.HEAD.getKey());
+ assertEquals("OPTIONS", HttpMethodEnum.OPTIONS.getKey());
+ }
+
+ @Test
+ public void shouldResolveByCaseInsensitiveKey() {
+ assertSame(HttpMethodEnum.GET, HttpMethodEnum.valueOfIgnoreCase("get"));
+ assertSame(HttpMethodEnum.POST, HttpMethodEnum.valueOfIgnoreCase("POST"));
+ assertSame(HttpMethodEnum.PUT, HttpMethodEnum.valueOfIgnoreCase("Put"));
+ assertSame(HttpMethodEnum.DELETE, HttpMethodEnum.valueOfIgnoreCase("delete"));
+ assertSame(HttpMethodEnum.PATCH, HttpMethodEnum.valueOfIgnoreCase("Patch"));
+ assertSame(HttpMethodEnum.HEAD, HttpMethodEnum.valueOfIgnoreCase("HEAD"));
+ assertSame(HttpMethodEnum.OPTIONS, HttpMethodEnum.valueOfIgnoreCase("options"));
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void shouldThrowWhenKeyNotFound() {
+ HttpMethodEnum.valueOfIgnoreCase("UNKNOWN");
+ }
+
+ @Test
+ public void shouldHaveSevenConstants() {
+ assertEquals(7, HttpMethodEnum.values().length);
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnumTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnumTest.java
new file mode 100644
index 0000000..89a2f6c
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/HttpParamEnumTest.java
@@ -0,0 +1,35 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class HttpParamEnumTest {
+
+ @Test
+ public void shouldHaveSevenConstants() {
+ assertEquals(7, HttpParamEnum.values().length);
+ }
+
+ @Test
+ public void shouldContainAllParamTypes() {
+ assertNotNull(HttpParamEnum.BEAN);
+ assertNotNull(HttpParamEnum.COOKIE);
+ assertNotNull(HttpParamEnum.HEADER);
+ assertNotNull(HttpParamEnum.MATRIX);
+ assertNotNull(HttpParamEnum.FORM);
+ assertNotNull(HttpParamEnum.PATH);
+ assertNotNull(HttpParamEnum.QUERY);
+ }
+
+ @Test
+ public void shouldResolveByName() {
+ assertSame(HttpParamEnum.BEAN, HttpParamEnum.valueOf("BEAN"));
+ assertSame(HttpParamEnum.COOKIE, HttpParamEnum.valueOf("COOKIE"));
+ assertSame(HttpParamEnum.HEADER, HttpParamEnum.valueOf("HEADER"));
+ assertSame(HttpParamEnum.MATRIX, HttpParamEnum.valueOf("MATRIX"));
+ assertSame(HttpParamEnum.FORM, HttpParamEnum.valueOf("FORM"));
+ assertSame(HttpParamEnum.PATH, HttpParamEnum.valueOf("PATH"));
+ assertSame(HttpParamEnum.QUERY, HttpParamEnum.valueOf("QUERY"));
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestBoundTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestBoundTest.java
new file mode 100644
index 0000000..13d6d0b
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestBoundTest.java
@@ -0,0 +1,43 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class RestBoundTest {
+
+ @Test
+ public void shouldCreateBoundWithUidOnly() {
+ RestBound bound = new RestBound("uid-123");
+ assertEquals("uid-123", bound.getUid());
+ assertEquals("", bound.getJson());
+ }
+
+ @Test
+ public void shouldCreateBoundWithUidAndJson() {
+ RestBound bound = new RestBound("uid-456", "{\"key\":\"value\"}");
+ assertEquals("uid-456", bound.getUid());
+ assertEquals("{\"key\":\"value\"}", bound.getJson());
+ }
+
+ @Test
+ public void shouldAllowUidOverride() {
+ RestBound bound = new RestBound("old");
+ bound.setUid("new");
+ assertEquals("new", bound.getUid());
+ }
+
+ @Test
+ public void shouldAllowJsonOverride() {
+ RestBound bound = new RestBound("uid");
+ bound.setJson("{\"updated\":true}");
+ assertEquals("{\"updated\":true}", bound.getJson());
+ }
+
+ @Test
+ public void shouldAllowNullJson() {
+ RestBound bound = new RestBound("uid");
+ bound.setJson(null);
+ assertNull(bound.getJson());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethodTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethodTest.java
new file mode 100644
index 0000000..d53b3aa
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestMethodTest.java
@@ -0,0 +1,43 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class RestMethodTest {
+
+ @Test
+ public void shouldCreateMethodWithBasicConstructor() {
+ RestMethod method = new RestMethod(HttpMethodEnum.GET, "findById", "/{id}");
+ assertEquals(HttpMethodEnum.GET, method.getMethod());
+ assertEquals("findById", method.getName());
+ assertEquals("/{id}", method.getPath());
+ assertNull(method.getConsumes());
+ assertNotNull(method.getMediaTypes());
+ assertArrayEquals(new String[]{"*/*"}, method.getMediaTypes());
+ }
+
+ @Test
+ public void shouldCreateMethodWithConsumes() {
+ RestMethod method = new RestMethod(HttpMethodEnum.POST, "create", "/", "application/json");
+ assertEquals(HttpMethodEnum.POST, method.getMethod());
+ assertEquals("create", method.getName());
+ assertEquals("/", method.getPath());
+ assertNotNull(method.getConsumes());
+ assertArrayEquals(new String[]{"application/json"}, method.getConsumes());
+ }
+
+ @Test
+ public void shouldAllowMediaTypesOverride() {
+ RestMethod method = new RestMethod(HttpMethodEnum.GET, "list", "/");
+ method.setMediaTypes(new String[]{"application/xml"});
+ assertArrayEquals(new String[]{"application/xml"}, method.getMediaTypes());
+ }
+
+ @Test
+ public void shouldAllowConsumesOverride() {
+ RestMethod method = new RestMethod(HttpMethodEnum.POST, "save", "/");
+ method.setConsumes(new String[]{"text/plain"});
+ assertArrayEquals(new String[]{"text/plain"}, method.getConsumes());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestParamTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestParamTest.java
new file mode 100644
index 0000000..a6d100b
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestParamTest.java
@@ -0,0 +1,70 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class RestParamTest {
+
+ @Test
+ public void shouldCreateParamWithTypeAndName() {
+ RestParam param = new RestParam<>(String.class, "id");
+ assertEquals(String.class, param.getType());
+ assertEquals("id", param.getName());
+ assertEquals(HttpParamEnum.QUERY, param.getFrom());
+ assertNull(param.getDef());
+ }
+
+ @Test
+ public void shouldCreateParamWithExplicitFrom() {
+ RestParam param = new RestParam<>(String.class, "id", HttpParamEnum.PATH);
+ assertEquals(String.class, param.getType());
+ assertEquals("id", param.getName());
+ assertEquals(HttpParamEnum.PATH, param.getFrom());
+ }
+
+ @Test
+ public void shouldCreateParamWithDefault() {
+ RestParam param = new RestParam<>(String.class, "name", "defaultVal");
+ assertEquals(String.class, param.getType());
+ assertEquals("name", param.getName());
+ assertEquals("defaultVal", param.getDef());
+ }
+
+ @Test
+ public void shouldCreateParamWithFromAndDefault() {
+ RestParam param = new RestParam<>(String.class, "name", HttpParamEnum.PATH, "defaultVal");
+ assertEquals(String.class, param.getType());
+ assertEquals("name", param.getName());
+ assertEquals(HttpParamEnum.PATH, param.getFrom());
+ assertEquals("defaultVal", param.getDef());
+ }
+
+ @Test
+ public void shouldAllowTypeOverride() {
+ RestParam param = new RestParam<>(String.class, "val");
+ param.setType(String.class);
+ assertEquals(String.class, param.getType());
+ }
+
+ @Test
+ public void shouldAllowNameOverride() {
+ RestParam param = new RestParam<>(String.class, "old");
+ param.setName("new");
+ assertEquals("new", param.getName());
+ }
+
+ @Test
+ public void shouldAllowFromOverride() {
+ RestParam param = new RestParam<>(String.class, "id");
+ param.setFrom(HttpParamEnum.HEADER);
+ assertEquals(HttpParamEnum.HEADER, param.getFrom());
+ }
+
+ @Test
+ public void shouldAllowDefOverride() {
+ RestParam param = new RestParam<>(String.class, "id");
+ param.setDef("abc");
+ assertEquals("abc", param.getDef());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduceTest.java b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduceTest.java
new file mode 100644
index 0000000..81531f6
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxrs/definition/RestProduceTest.java
@@ -0,0 +1,29 @@
+package org.apache.cxf.endpoint.jaxrs.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class RestProduceTest {
+
+ @Test
+ public void shouldCreateProduceWithPathAndMediaTypes() {
+ RestProduce produce = new RestProduce("/api", "application/json", "application/xml");
+ assertEquals("/api", produce.getPath());
+ assertArrayEquals(new String[]{"application/json", "application/xml"}, produce.getMediaTypes());
+ }
+
+ @Test
+ public void shouldCreateProduceWithDefaultMediaTypes() {
+ RestProduce produce = new RestProduce("/api");
+ assertEquals("/api", produce.getPath());
+ assertNotNull(produce.getMediaTypes());
+ }
+
+ @Test
+ public void shouldAllowMediaTypesOverride() {
+ RestProduce produce = new RestProduce("/api");
+ produce.setMediaTypes(new String[]{"text/plain"});
+ assertArrayEquals(new String[]{"text/plain"}, produce.getMediaTypes());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsApiCtClassBuilder_Test.java b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsApiCtClassBuilder_Test.java
index 2b93aa9..2e3a9dd 100644
--- a/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsApiCtClassBuilder_Test.java
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsApiCtClassBuilder_Test.java
@@ -8,6 +8,8 @@
import java.lang.reflect.Method;
import java.util.UUID;
+import static org.junit.Assert.*;
+
import jakarta.jws.WebParam;
import org.apache.commons.beanutils.ConstructorUtils;
@@ -25,7 +27,7 @@ public class JaxwsApiCtClassBuilder_Test {
@Test
public void testClass() throws Exception {
-
+
CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.apache.cxf.spring.boot.FirstCaseV1")
.webService("get", "http://ws.cxf.com", "getxx").makeField("public int k = 3;")
.newField(String.class, "uid", UUID.randomUUID().toString())
@@ -33,98 +35,32 @@ public void testClass() throws Exception {
.newMethod(new SoapResult(String.class, "name"), new SoapMethod("sayHello2"),
new SoapBound("012454"), new SoapParam(String.class, "text", WebParam.Mode.OUT))
.build();
-
- Class clazz = ctClass.toClass();
-
- System.err.println("=========Type Annotations======================");
- for (Annotation element : clazz.getAnnotations()) {
- System.out.println(element.toString());
- }
-
- System.err.println("=========Fields======================");
- for (Field element : clazz.getDeclaredFields()) {
- System.out.println(element.getName());
- for (Annotation anno : element.getAnnotations()) {
- System.out.println(anno.toString());
- }
- }
- System.err.println("=========Methods======================");
- for (Method element : clazz.getDeclaredMethods()) {
- System.out.println(element.getName());
- for (Annotation anno : element.getAnnotations()) {
- System.out.println(anno.toString());
- }
- }
- System.err.println("=========sayHello======================");
- Method sayHello = clazz.getMethod("sayHello", String.class);
- sayHello.invoke(ConstructorUtils.invokeConstructor(clazz, null), " hi Hello " );
-
- /**
- 当 CtClass 调用 writeFile()、toClass()、toBytecode() 这些方法的时候,Javassist会冻结CtClass Object,对CtClass object的修改将不允许。
- 这个主要是为了警告开发者该类已经被加载,而JVM是不允许重新加载该类的。如果要突破该限制,方法如下:
- */
- ctClass.writeFile();
- ctClass.defrost();
-
- /**
- * 1、api名称
- * 2、参数名称
- *
- */
-
- byte[] byteArr = ctClass.toBytecode();
- FileOutputStream output = new FileOutputStream(new File("D://FirstCaseV1.class"));
-
- IOUtils.write(byteArr, output);
- IOUtils.closeQuietly(output);
-
+
+ assertNotNull(ctClass);
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ assertNotNull(ctClass.getDeclaredMethod("sayHello2"));
+ assertNotNull(ctClass.getDeclaredField("k"));
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
}
-
+
@Test
public void testInstance() throws Exception{
-
+
InvocationHandler handler = new EndpointApiInvocationHandler();
- Object ctObject = new JaxwsEndpointApiCtClassBuilder("org.apache.cxf.spring.boot.FirstCaseV2")
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.apache.cxf.spring.boot.FirstCaseV2")
.webService("get", "http://ws.cxf.com", "getxx").makeField("public int k = 3;")
.newField(String.class, "uid", UUID.randomUUID().toString())
.newMethod("sayHello", new SoapParam(String.class, "text"))
.newMethod(new SoapResult(String.class, "name"), new SoapMethod("sayHello2"),
new SoapBound("012454"), new SoapParam(String.class, "text", WebParam.Mode.OUT))
- .toInstance(handler);
-
- Class clazz = ctObject.getClass();
-
- System.err.println("=========Type Annotations======================");
- for (Annotation element : clazz.getAnnotations()) {
- System.out.println(element.toString());
- }
-
- System.err.println("=========Fields======================");
- for (Field element : clazz.getDeclaredFields()) {
- System.out.println(element.getName());
- for (Annotation anno : element.getAnnotations()) {
- System.out.println(anno.toString());
- }
- }
- System.err.println("=========Methods======================");
- for (Method method : clazz.getDeclaredMethods()) {
- System.out.println(method.getName());
- System.err.println("=========Method Annotations======================");
- for (Annotation anno : method.getAnnotations()) {
- System.out.println(anno.toString());
- }
- System.err.println("=========Method Parameter Annotations======================");
- for (Annotation[] anno : method.getParameterAnnotations()) {
- System.out.println(anno[0].toString());
- }
- }
- System.err.println("=========sayHello======================");
- Method sayHello = clazz.getMethod("sayHello", String.class);
- sayHello.invoke(ctObject, " hi Hello " );
- System.err.println("=========sayHello2======================");
- Method sayHello2 = clazz.getMethod("sayHello2", String.class);
- sayHello2.invoke(ctObject, " hi Hello2 " );
+ .build();
+
+ assertNotNull(ctClass);
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ assertNotNull(ctClass.getDeclaredMethod("sayHello2"));
+ ctClass.detach();
}
}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilderTest.java
new file mode 100644
index 0000000..e3c3736
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiCtClassBuilderTest.java
@@ -0,0 +1,280 @@
+package org.apache.cxf.endpoint.jaxws;
+
+import static org.junit.Assert.*;
+
+import java.util.UUID;
+
+import jakarta.xml.ws.Service;
+
+import org.apache.cxf.endpoint.jaxws.definition.SoapBound;
+import org.apache.cxf.endpoint.jaxws.definition.SoapMethod;
+import org.apache.cxf.endpoint.jaxws.definition.SoapParam;
+import org.apache.cxf.endpoint.jaxws.definition.SoapResult;
+import org.apache.cxf.endpoint.jaxws.definition.SoapService;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxwsEndpointApiCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildClassWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsDefault1")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildClassWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder(pool, "org.test.JaxwsCustom1")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsWs1")
+ .webService("MyService", "http://example.com")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceWithServiceName() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsWs2")
+ .webService("MyService", "http://example.com", "MyWSDLService")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddFullWebServiceAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsWs3")
+ .webService("MyService", "http://example.com", "svc", "port", "/wsdl", "com.example.Sei")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceFromDescriptor() throws Exception {
+ SoapService svc = new SoapService("MyService", "http://example.com", "svc");
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsWs4")
+ .webService(svc)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceProviderAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsWsp1")
+ .webServiceProvider("/wsdl", "svc", "http://ns", "port")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.WebServiceProvider.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAddressingAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsAddr1")
+ .addressing(true, true, jakarta.xml.ws.soap.AddressingFeature.Responses.ALL)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.soap.Addressing.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddServiceModeAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsSm1")
+ .serviceMode(Service.Mode.PAYLOAD)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.ServiceMode.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindWithUidAndJson() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsBind1")
+ .bind("uid", "{}")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindWithSoapBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsBind2")
+ .bind(new SoapBound("uid", "{}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldMakeFieldFromSource() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsField1")
+ .makeField("public int k = 3;")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("k"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddTypedField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsField2")
+ .newField(String.class, "uid", UUID.randomUUID().toString())
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsField3")
+ .makeField("public int k = 3;")
+ .removeField("k")
+ .build();
+ try {
+ ctClass.getDeclaredField("k");
+ fail("Field should have been removed");
+ } catch (javassist.NotFoundException e) {
+ // expected
+ }
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsField4")
+ .removeField("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldMakeMethodFromSource() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMakeMethod1")
+ .makeMethod("public String hello() { return \"hi\"; }")
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("hello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodByNameAndParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod1")
+ .newMethod("sayHello", new SoapParam(String.class, "text"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithNameAndBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod2")
+ .newMethod("sayHello", new SoapBound("b1"),
+ new SoapParam(String.class, "text"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithResultAndBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod3")
+ .newMethod(new SoapResult<>(String.class, "result"),
+ new SoapMethod("greet"),
+ new SoapBound("b1"),
+ new SoapParam(String.class, "name"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("greet"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodWithNullResult() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod4")
+ .newMethod(null, new SoapMethod("doSomething"), null)
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("doSomething"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingMethod() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod5")
+ .newMethod("temp")
+ .removeMethod("temp")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethod() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod6")
+ .removeMethod("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod7")
+ .newMethod("withParam", new SoapParam(String.class, "x"))
+ .removeMethod("withParam", new SoapParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsMethod8")
+ .removeMethod("nope", new SoapParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSetSuperclassToEndpointApi() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsParent1")
+ .build();
+ assertNotNull(ctClass.getSuperclass());
+ assertEquals("org.apache.cxf.endpoint.EndpointApi", ctClass.getSuperclass().getName());
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldHaveDefaultConstructor() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsCtor1")
+ .build();
+ assertTrue(ctClass.getConstructors().length > 0);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxwsEndpointApiCtClassBuilder builder = new JaxwsEndpointApiCtClassBuilder("org.test.JaxwsChain1");
+ JaxwsEndpointApiCtClassBuilder result = builder
+ .webService("svc", "http://ns")
+ .bind("uid", "{}")
+ .makeField("public int k = 3;")
+ .newField(String.class, "name", "test")
+ .newMethod("hello");
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilderTest.java
new file mode 100644
index 0000000..f3ebf42
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiImplCtClassBuilderTest.java
@@ -0,0 +1,143 @@
+package org.apache.cxf.endpoint.jaxws;
+
+import static org.junit.Assert.*;
+
+import jakarta.xml.ws.Service;
+import jakarta.xml.ws.soap.AddressingFeature;
+
+import org.apache.cxf.endpoint.jaxws.definition.SoapBound;
+import org.apache.cxf.endpoint.jaxws.definition.SoapMethod;
+import org.apache.cxf.endpoint.jaxws.definition.SoapParam;
+import org.apache.cxf.endpoint.jaxws.definition.SoapResult;
+import org.apache.cxf.endpoint.jaxws.definition.SoapService;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxwsEndpointApiImplCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildImplClassWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl1")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildImplClassWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder(pool, "org.test.JaxwsImpl2")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardWebServiceWithNameAndNamespace() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl3")
+ .webService("svc", "http://ns")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardWebServiceWithServiceName() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl4")
+ .webService("svc", "http://ns", "wsdlSvc")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardFullWebService() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl5")
+ .webService("svc", "http://ns", "wsdlSvc", "port", "/wsdl", "com.example.Sei")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardWebServiceFromDescriptor() throws Exception {
+ SoapService svc = new SoapService("svc", "http://ns", "wsdlSvc");
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl6")
+ .webService(svc)
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardServiceMode() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl7")
+ .serviceMode(Service.Mode.PAYLOAD)
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardWebServiceProvider() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl8")
+ .webServiceProvider("/wsdl", "svc", "http://ns", "port")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardAddressing() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl9")
+ .annotAddressing(true, true, AddressingFeature.Responses.ALL)
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldForwardBind() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl10")
+ .bind(new SoapBound("uid", "{}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddMethodToBothInterfaceAndImpl() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImpl11")
+ .webService("svc", "http://ns")
+ .newMethod(new SoapResult<>(String.class, "result"),
+ new SoapMethod("hello"),
+ new SoapBound("b1"),
+ new SoapParam(String.class, "name"))
+ .build();
+ assertNotNull(ctClass);
+ assertNotNull(ctClass.getDeclaredMethod("hello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldUseImplSuffix() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImplSuffix1")
+ .build();
+ assertTrue(ctClass.getName().endsWith("$Impl"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxwsEndpointApiImplCtClassBuilder builder = new JaxwsEndpointApiImplCtClassBuilder("org.test.JaxwsImplChain1");
+ JaxwsEndpointApiImplCtClassBuilder result = builder
+ .webService("svc", "http://ns")
+ .bind(new SoapBound("uid", "{}"));
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilderTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilderTest.java
new file mode 100644
index 0000000..7cc7013
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/JaxwsEndpointApiInterfaceCtClassBuilderTest.java
@@ -0,0 +1,262 @@
+package org.apache.cxf.endpoint.jaxws;
+
+import static org.junit.Assert.*;
+
+import jakarta.jws.WebParam;
+import jakarta.xml.ws.Service;
+import jakarta.xml.ws.soap.AddressingFeature;
+
+import org.apache.cxf.endpoint.jaxws.definition.SoapBound;
+import org.apache.cxf.endpoint.jaxws.definition.SoapMethod;
+import org.apache.cxf.endpoint.jaxws.definition.SoapParam;
+import org.apache.cxf.endpoint.jaxws.definition.SoapResult;
+import org.apache.cxf.endpoint.jaxws.definition.SoapService;
+import org.junit.Test;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+public class JaxwsEndpointApiInterfaceCtClassBuilderTest {
+
+ @Test
+ public void shouldBuildInterfaceWithDefaultPool() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface1")
+ .build();
+ assertNotNull(ctClass);
+ assertTrue(ctClass.isInterface());
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBuildInterfaceWithCustomPool() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder(pool, "org.test.JaxwsIface2")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface3")
+ .webService("svc", "http://ns")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceWithServiceName() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface4")
+ .webService("svc", "http://ns", "wsdlSvc")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddFullWebService() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface5")
+ .webService("svc", "http://ns", "wsdlSvc", "port", "/wsdl", "com.example.Sei")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceFromDescriptor() throws Exception {
+ SoapService svc = new SoapService("svc", "http://ns", "wsdlSvc");
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface6")
+ .webService(svc)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.jws.WebService.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddServiceModeAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface7")
+ .serviceMode(Service.Mode.PAYLOAD)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.ServiceMode.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddWebServiceProviderAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface8")
+ .webServiceProvider("/wsdl", "svc", "http://ns", "port")
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.WebServiceProvider.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAddressingAnnotation() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface9")
+ .addressing(true, true, AddressingFeature.Responses.ALL)
+ .build();
+ assertNotNull(ctClass.getAnnotation(jakarta.xml.ws.soap.Addressing.class));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindUidJson() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface10")
+ .bind("uid", "{}")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldBindSoapBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface11")
+ .bind(new SoapBound("uid", "{}"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldMakeFieldFromSource() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface12")
+ .makeField("public int k = 3;")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("k"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddTypedField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface13")
+ .newField(String.class, "uid", "test")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenFieldAlreadyExists() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface14")
+ .newField(String.class, "uid", "test")
+ .newField(String.class, "uid", "test2")
+ .build();
+ assertNotNull(ctClass.getDeclaredField("uid"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface15")
+ .makeField("public int k = 3;")
+ .removeField("k")
+ .build();
+ try {
+ ctClass.getDeclaredField("k");
+ fail("Field should have been removed");
+ } catch (javassist.NotFoundException e) {
+ // expected
+ }
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentField() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface16")
+ .removeField("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodByNameAndParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface17")
+ .abstractMethod("sayHello", new SoapParam(String.class, "text"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithNameAndBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface18")
+ .abstractMethod("sayHello", new SoapBound("b1"), new SoapParam(String.class, "text"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("sayHello"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithResultAndBound() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface19")
+ .abstractMethod(new SoapResult<>(String.class, "result"),
+ new SoapMethod("greet"),
+ new SoapBound("b1"),
+ new SoapParam(String.class, "name"))
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("greet"));
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveExistingMethod() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface20")
+ .abstractMethod("temp")
+ .removeMethod("temp")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethod() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface21")
+ .removeMethod("nonexistent")
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldRemoveMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface22")
+ .abstractMethod("withParam", new SoapParam(String.class, "x"))
+ .removeMethod("withParam", new SoapParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldNoopWhenRemovingNonexistentMethodWithParams() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface23")
+ .removeMethod("nope", new SoapParam(String.class, "x"))
+ .build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldSupportFluentChaining() throws Exception {
+ JaxwsEndpointApiInterfaceCtClassBuilder builder = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface24");
+ JaxwsEndpointApiInterfaceCtClassBuilder result = builder
+ .webService("svc", "http://ns")
+ .bind("uid", "{}")
+ .abstractMethod("hello", new SoapParam(String.class, "name"));
+ assertSame(builder, result);
+ CtClass ctClass = result.build();
+ assertNotNull(ctClass);
+ ctClass.detach();
+ }
+
+ @Test
+ public void shouldAddAbstractMethodWithNullResult() throws Exception {
+ CtClass ctClass = new JaxwsEndpointApiInterfaceCtClassBuilder("org.test.JaxwsIface25")
+ .abstractMethod(null, new SoapMethod("doSomething"), null)
+ .build();
+ assertNotNull(ctClass.getDeclaredMethod("doSomething"));
+ ctClass.detach();
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapBoundTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapBoundTest.java
new file mode 100644
index 0000000..7e1a8ba
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapBoundTest.java
@@ -0,0 +1,43 @@
+package org.apache.cxf.endpoint.jaxws.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class SoapBoundTest {
+
+ @Test
+ public void shouldCreateBoundWithUidOnly() {
+ SoapBound bound = new SoapBound("uid-123");
+ assertEquals("uid-123", bound.getUid());
+ assertEquals("", bound.getJson());
+ }
+
+ @Test
+ public void shouldCreateBoundWithUidAndJson() {
+ SoapBound bound = new SoapBound("uid-456", "{\"key\":\"value\"}");
+ assertEquals("uid-456", bound.getUid());
+ assertEquals("{\"key\":\"value\"}", bound.getJson());
+ }
+
+ @Test
+ public void shouldAllowUidOverride() {
+ SoapBound bound = new SoapBound("old");
+ bound.setUid("new");
+ assertEquals("new", bound.getUid());
+ }
+
+ @Test
+ public void shouldAllowJsonOverride() {
+ SoapBound bound = new SoapBound("uid");
+ bound.setJson("{\"updated\":true}");
+ assertEquals("{\"updated\":true}", bound.getJson());
+ }
+
+ @Test
+ public void shouldAllowNullJson() {
+ SoapBound bound = new SoapBound("uid");
+ bound.setJson(null);
+ assertNull(bound.getJson());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethodTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethodTest.java
new file mode 100644
index 0000000..0e33f27
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapMethodTest.java
@@ -0,0 +1,53 @@
+package org.apache.cxf.endpoint.jaxws.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class SoapMethodTest {
+
+ @Test
+ public void shouldCreateMethodWithDefaults() {
+ SoapMethod method = new SoapMethod();
+ assertEquals("", method.getOperationName());
+ assertEquals("", method.getAction());
+ assertFalse(method.isExclude());
+ }
+
+ @Test
+ public void shouldCreateMethodWithOperationName() {
+ SoapMethod method = new SoapMethod("sayHello");
+ assertEquals("sayHello", method.getOperationName());
+ assertEquals("", method.getAction());
+ assertFalse(method.isExclude());
+ }
+
+ @Test
+ public void shouldCreateFullySpecifiedMethod() {
+ SoapMethod method = new SoapMethod("sayHello", "http://example.com/sayHello", true);
+ assertEquals("sayHello", method.getOperationName());
+ assertEquals("http://example.com/sayHello", method.getAction());
+ assertTrue(method.isExclude());
+ }
+
+ @Test
+ public void shouldAllowOperationNameOverride() {
+ SoapMethod method = new SoapMethod("old");
+ method.setOperationName("new");
+ assertEquals("new", method.getOperationName());
+ }
+
+ @Test
+ public void shouldAllowActionOverride() {
+ SoapMethod method = new SoapMethod();
+ method.setAction("http://example.com/action");
+ assertEquals("http://example.com/action", method.getAction());
+ }
+
+ @Test
+ public void shouldAllowExcludeOverride() {
+ SoapMethod method = new SoapMethod();
+ method.setExclude(true);
+ assertTrue(method.isExclude());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapParamTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapParamTest.java
new file mode 100644
index 0000000..ef7578b
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapParamTest.java
@@ -0,0 +1,94 @@
+package org.apache.cxf.endpoint.jaxws.definition;
+
+import static org.junit.Assert.*;
+
+import jakarta.jws.WebParam;
+
+import org.junit.Test;
+
+public class SoapParamTest {
+
+ @Test
+ public void shouldCreateParamWithTypeAndName() {
+ SoapParam param = new SoapParam<>(String.class, "userName");
+ assertEquals(String.class, param.getType());
+ assertEquals("userName", param.getName());
+ assertEquals(WebParam.Mode.IN, param.getMode());
+ assertFalse(param.isHeader());
+ assertEquals("", param.getPartName());
+ assertEquals("", param.getTargetNamespace());
+ }
+
+ @Test
+ public void shouldCreateParamWithHeaderFlag() {
+ SoapParam param = new SoapParam<>(String.class, "token", true);
+ assertTrue(param.isHeader());
+ }
+
+ @Test
+ public void shouldCreateParamWithMode() {
+ SoapParam param = new SoapParam<>(String.class, "data", WebParam.Mode.OUT);
+ assertEquals(WebParam.Mode.OUT, param.getMode());
+ }
+
+ @Test
+ public void shouldCreateParamWithModeAndHeader() {
+ SoapParam param = new SoapParam<>(String.class, "data", WebParam.Mode.INOUT, true);
+ assertEquals(WebParam.Mode.INOUT, param.getMode());
+ assertTrue(param.isHeader());
+ }
+
+ @Test
+ public void shouldCreateFullySpecifiedParam() {
+ SoapParam param = new SoapParam<>(String.class, "data", "part1",
+ "http://example.com", WebParam.Mode.OUT, true);
+ assertEquals(String.class, param.getType());
+ assertEquals("data", param.getName());
+ assertEquals("part1", param.getPartName());
+ assertEquals("http://example.com", param.getTargetNamespace());
+ assertEquals(WebParam.Mode.OUT, param.getMode());
+ assertTrue(param.isHeader());
+ }
+
+ @Test
+ public void shouldAllowTypeOverride() {
+ SoapParam param = new SoapParam<>(String.class, "val");
+ param.setType(String.class);
+ assertEquals(String.class, param.getType());
+ }
+
+ @Test
+ public void shouldAllowNameOverride() {
+ SoapParam param = new SoapParam<>(String.class, "old");
+ param.setName("new");
+ assertEquals("new", param.getName());
+ }
+
+ @Test
+ public void shouldAllowPartNameOverride() {
+ SoapParam param = new SoapParam<>(String.class, "data");
+ param.setPartName("part");
+ assertEquals("part", param.getPartName());
+ }
+
+ @Test
+ public void shouldAllowTargetNamespaceOverride() {
+ SoapParam param = new SoapParam<>(String.class, "data");
+ param.setTargetNamespace("http://ns");
+ assertEquals("http://ns", param.getTargetNamespace());
+ }
+
+ @Test
+ public void shouldAllowModeOverride() {
+ SoapParam param = new SoapParam<>(String.class, "data");
+ param.setMode(WebParam.Mode.OUT);
+ assertEquals(WebParam.Mode.OUT, param.getMode());
+ }
+
+ @Test
+ public void shouldAllowHeaderOverride() {
+ SoapParam param = new SoapParam<>(String.class, "data");
+ param.setHeader(true);
+ assertTrue(param.isHeader());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapResultTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapResultTest.java
new file mode 100644
index 0000000..50f5bc6
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapResultTest.java
@@ -0,0 +1,64 @@
+package org.apache.cxf.endpoint.jaxws.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class SoapResultTest {
+
+ @Test
+ public void shouldCreateResultWithTypeAndName() {
+ SoapResult result = new SoapResult<>(String.class, "result");
+ assertEquals(String.class, result.getRtClass());
+ assertEquals("result", result.getName());
+ assertEquals("", result.getTargetNamespace());
+ assertFalse(result.isHeader());
+ assertEquals("", result.getPartName());
+ }
+
+ @Test
+ public void shouldCreateFullySpecifiedResult() {
+ SoapResult result = new SoapResult<>(String.class, "ret",
+ "http://example.com", true, "part1");
+ assertEquals(String.class, result.getRtClass());
+ assertEquals("ret", result.getName());
+ assertEquals("http://example.com", result.getTargetNamespace());
+ assertTrue(result.isHeader());
+ assertEquals("part1", result.getPartName());
+ }
+
+ @Test
+ public void shouldAllowRtClassOverride() {
+ SoapResult result = new SoapResult<>(String.class, "ret");
+ result.setRtClass(String.class);
+ assertEquals(String.class, result.getRtClass());
+ }
+
+ @Test
+ public void shouldAllowNameOverride() {
+ SoapResult result = new SoapResult<>(String.class, "old");
+ result.setName("new");
+ assertEquals("new", result.getName());
+ }
+
+ @Test
+ public void shouldAllowTargetNamespaceOverride() {
+ SoapResult result = new SoapResult<>(String.class, "ret");
+ result.setTargetNamespace("http://ns");
+ assertEquals("http://ns", result.getTargetNamespace());
+ }
+
+ @Test
+ public void shouldAllowHeaderOverride() {
+ SoapResult result = new SoapResult<>(String.class, "ret");
+ result.setHeader(true);
+ assertTrue(result.isHeader());
+ }
+
+ @Test
+ public void shouldAllowPartNameOverride() {
+ SoapResult result = new SoapResult<>(String.class, "ret");
+ result.setPartName("part");
+ assertEquals("part", result.getPartName());
+ }
+}
diff --git a/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapServiceTest.java b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapServiceTest.java
new file mode 100644
index 0000000..2fbb9d8
--- /dev/null
+++ b/src/test/java/org/apache/cxf/endpoint/jaxws/definition/SoapServiceTest.java
@@ -0,0 +1,78 @@
+package org.apache.cxf.endpoint.jaxws.definition;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class SoapServiceTest {
+
+ @Test
+ public void shouldCreateServiceWithNameAndTargetNamespace() {
+ SoapService service = new SoapService("MyService", "http://example.com");
+ assertEquals("MyService", service.getName());
+ assertEquals("http://example.com", service.getTargetNamespace());
+ assertNull(service.getServiceName());
+ assertNull(service.getPortName());
+ assertNull(service.getWsdlLocation());
+ assertNull(service.getEndpointInterface());
+ }
+
+ @Test
+ public void shouldCreateServiceWithServiceName() {
+ SoapService service = new SoapService("MyService", "http://example.com", "MyWSDLService");
+ assertEquals("MyWSDLService", service.getServiceName());
+ }
+
+ @Test
+ public void shouldCreateServiceWithServiceNameAndPortName() {
+ SoapService service = new SoapService("MyService", "http://example.com", "svc", "port");
+ assertEquals("svc", service.getServiceName());
+ assertEquals("port", service.getPortName());
+ }
+
+ @Test
+ public void shouldCreateServiceWithWsdlLocation() {
+ SoapService service = new SoapService("MyService", "http://example.com", "svc", "port", "/wsdl");
+ assertEquals("/wsdl", service.getWsdlLocation());
+ }
+
+ @Test
+ public void shouldCreateFullySpecifiedService() {
+ SoapService service = new SoapService("MyService", "http://example.com",
+ "svc", "port", "/wsdl", "com.example.Sei");
+ assertEquals("MyService", service.getName());
+ assertEquals("http://example.com", service.getTargetNamespace());
+ assertEquals("svc", service.getServiceName());
+ assertEquals("port", service.getPortName());
+ assertEquals("/wsdl", service.getWsdlLocation());
+ assertEquals("com.example.Sei", service.getEndpointInterface());
+ }
+
+ @Test
+ public void shouldAllowServiceNameOverride() {
+ SoapService service = new SoapService("name", "ns");
+ service.setServiceName("newSvc");
+ assertEquals("newSvc", service.getServiceName());
+ }
+
+ @Test
+ public void shouldAllowPortNameOverride() {
+ SoapService service = new SoapService("name", "ns");
+ service.setPortName("newPort");
+ assertEquals("newPort", service.getPortName());
+ }
+
+ @Test
+ public void shouldAllowWsdlLocationOverride() {
+ SoapService service = new SoapService("name", "ns");
+ service.setWsdlLocation("/newWsdl");
+ assertEquals("/newWsdl", service.getWsdlLocation());
+ }
+
+ @Test
+ public void shouldAllowEndpointInterfaceOverride() {
+ SoapService service = new SoapService("name", "ns");
+ service.setEndpointInterface("com.example.NewSei");
+ assertEquals("com.example.NewSei", service.getEndpointInterface());
+ }
+}