You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置项目排除JSON序列化中的Weld元数据?

Fixing Extra metadata Field in JSON Responses with Weld & Yasson

Hey there! I've dealt with this exact problem before—those unwanted metadata fields are coming from the dynamic proxy objects Weld creates for your CDI beans. Yasson (the JSON-B implementation) is serializing all the proxy's internal fields by default, which is why you're seeing that extra nested data. Let's go through the most reliable solutions:

Solution 1: Disable Proxy Type Serialization via Yasson Config

This is the most robust approach, as it configures Yasson to ignore CDI proxy metadata entirely. You'll need to create a custom JAX-RS ContextResolver to set up the Jsonb configuration:

First, create the resolver class:

import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.Provider;
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.JsonbConfig;

@Provider
public class JsonbProxyFixResolver implements ContextResolver<Jsonb> {
    private final Jsonb jsonb;

    public JsonbProxyFixResolver() {
        // Disable serialization of proxy types to skip Weld's extra fields
        JsonbConfig config = new JsonbConfig()
                .setProperty(JsonbConfig.PROPERTY_SERIALIZE_PROXY_TYPES, false);
        this.jsonb = JsonbBuilder.create(config);
    }

    @Override
    public Jsonb getContext(Class<?> type) {
        return jsonb;
    }
}

Then register this resolver in your JAX-RS application class:

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

@ApplicationPath("/")
public class YourJaxrsApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(ActiveLeadTask.class);
        classes.add(JsonbProxyFixResolver.class); // Add our resolver here
        return classes;
    }
}

This tells Yasson to detect proxy objects and serialize the actual underlying bean instance instead of the proxy, which eliminates the metadata field entirely.

If you can't modify the global Jsonb config, you can create a custom serializer to extract the real bean from the Weld proxy. Note: This relies on Weld's internal proxy structure, which might change between versions, so use with caution.

First, create the serializer:

import jakarta.json.bind.serializer.JsonbSerializer;
import jakarta.json.bind.serializer.SerializationContext;
import jakarta.json.stream.JsonGenerator;
import java.lang.reflect.Field;

public class CdiBeanProxySerializer<T> implements JsonbSerializer<T> {
    @Override
    public void serialize(T proxyObj, JsonGenerator generator, SerializationContext ctx) {
        try {
            // Extract the real bean instance from Weld's proxy
            Field instanceField = proxyObj.getClass().getDeclaredField("instance");
            instanceField.setAccessible(true);
            T realBean = (T) instanceField.get(proxyObj);
            ctx.serialize(realBean, generator);
        } catch (Exception e) {
            // Fall back to serializing the original object if it's not a proxy
            ctx.serialize(proxyObj, generator);
        }
    }
}

Then annotate your ActiveLeadTaskBo class to use this serializer:

import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;

@XmlRootElement
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@JsonbTypeSerializer(CdiBeanProxySerializer.class) // Add this annotation
public class ActiveLeadTaskBo implements Serializable {
    private static final long serialVersionUID = 1L;
    private String firstName;
    private String lastName;
    private String phoneNumber;
    private String phoneCountryCode;
    private AtomicInteger accessCounterField = new AtomicInteger(0);

    public ActiveLeadTaskBo() {
        firstName = "test";
        lastName = "test";
    }

    // ... Your existing getters/setters ...
}

Solution 3: Fetch the Real Bean via Provider (Edge Case)

For some CDI scopes (like @ApplicationScoped), you can use a Provider to get the unproxied bean instance directly in your resource:

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.inject.Provider;

@Path("/ActiveLeadTask")
@Produces(MediaType.APPLICATION_JSON)
public class ActiveLeadTask {
    private @Inject Provider<ActiveLeadTaskBo> activeLeadBoProvider; // Use Provider instead of direct injection

    @GET
    @Path("/getBo")
    public ActiveLeadTaskBo getBo() {
        return activeLeadBoProvider.get(); // Returns the real bean instance
    }
}

This works in some scenarios but isn't universal—stick with Solution 1 for the most consistent results.

Why This Happens

Weld creates dynamic proxy objects for CDI beans to handle context management, dependency injection, and interception. These proxies include internal fields like metadata and instance that hold the real bean. Yasson's default behavior is to serialize all accessible fields of an object, so it picks up these proxy-specific fields unless configured otherwise.

内容的提问来源于stack exchange,提问作者aleksander_si

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:46:12