New adapter: HypeLab#4488
Open
Minebomber wants to merge 1 commit into
Open
Conversation
CTMBNara
requested changes
May 13, 2026
| } | ||
|
|
||
| if (validImps.isEmpty()) { | ||
| return Result.of(Collections.emptyList(), errors); |
Comment on lines
+76
to
+85
| return Result.of(Collections.singletonList( | ||
| HttpRequest.<BidRequest>builder() | ||
| .method(HttpMethod.POST) | ||
| .uri(endpointUrl) | ||
| .headers(headers()) | ||
| .impIds(BidderUtil.impIds(outgoingRequest)) | ||
| .body(mapper.encodeToBytes(outgoingRequest)) | ||
| .payload(outgoingRequest) | ||
| .build()), | ||
| errors); |
Collaborator
There was a problem hiding this comment.
Use BidderUtil.defaultRequest
| } | ||
|
|
||
| private Imp makeOutgoingImp(Imp imp) { | ||
| final ExtImpHypeLab extImp = parseImpExt(imp); |
Collaborator
There was a problem hiding this comment.
Move parsing out of this method
Comment on lines
+101
to
+108
| if (imp.getExt() == null) { | ||
| throw new PreBidException("imp %s: unable to unmarshal ext".formatted(imp.getId())); | ||
| } | ||
|
|
||
| final JsonNode bidderNode = imp.getExt().get("bidder"); | ||
| if (bidderNode == null || bidderNode.isNull()) { | ||
| throw new PreBidException("imp %s: unable to unmarshal ext.bidder".formatted(imp.getId())); | ||
| } |
|
|
||
| final ExtImpHypeLab extImp; | ||
| try { | ||
| extImp = mapper.mapper().convertValue(bidderNode, ExtImpHypeLab.class); |
Collaborator
There was a problem hiding this comment.
Use TypeReference<ExtPrebid<?, ExtImpHypeLab>> instead
Comment on lines
+154
to
+183
| private static List<BidderBid> extractBids(BidRequest request, BidResponse response, List<BidderError> errors) { | ||
| if (response == null || CollectionUtils.isEmpty(response.getSeatbid())) { | ||
| return Collections.emptyList(); | ||
| } | ||
|
|
||
| final Map<String, Imp> impIdToImp = request.getImp().stream() | ||
| .collect(Collectors.toMap(Imp::getId, imp -> imp)); | ||
|
|
||
| return response.getSeatbid().stream() | ||
| .filter(Objects::nonNull) | ||
| .map(seatBid -> bidsFromSeatBid(seatBid, impIdToImp, response.getCur(), errors)) | ||
| .flatMap(Collection::stream) | ||
| .toList(); | ||
| } | ||
|
|
||
| private static List<BidderBid> bidsFromSeatBid(SeatBid seatBid, Map<String, Imp> impIdToImp, String currency, | ||
| List<BidderError> errors) { | ||
|
|
||
| final List<Bid> bids = seatBid.getBid(); | ||
| if (CollectionUtils.isEmpty(bids)) { | ||
| return Collections.emptyList(); | ||
| } | ||
|
|
||
| return bids.stream() | ||
| .filter(Objects::nonNull) | ||
| .map(bid -> makeBidderBid(bid, seatBid.getSeat(), impIdToImp, currency, errors)) | ||
| .filter(Objects::nonNull) | ||
| .toList(); | ||
| } | ||
|
|
Collaborator
There was a problem hiding this comment.
private static List<BidderBid> extractBids(BidRequest request, BidResponse response, List<BidderError> errors) {
if (response == null || CollectionUtils.isEmpty(response.getSeatbid())) {
return Collections.emptyList();
}
final Map<String, Imp> impIdToImp = request.getImp().stream()
.collect(Collectors.toMap(Imp::getId, imp -> imp));
return response.getSeatbid().stream()
.filter(Objects::nonNull)
.flatMap(seatBid -> CollectionUtils.emptyIfNull(seatBid.getBid()).stream()
.filter(Objects::nonNull)
.map(bid -> makeBidderBid(bid, seatBid.getSeat(), impIdToImp, response.getCur(), errors))
.filter(Objects::nonNull))
.toList();
}
private static BidderBid makeBidderBid(Bid bid,
String seat,
Map<String, Imp> impIdToImp, String currency,
List<BidderError> errors) {
try {
return BidderBid.of(bid, resolveBidType(bid, impIdToImp), seat, currency);
} catch (PreBidException e) {
errors.add(BidderError.badServerResponse(e.getMessage()));
return null;
}
}
private static BidType resolveBidType(Bid bid, Map<String, Imp> impIdToImp) {
return bidTypeFromMtype(bid.getMtype())
.or(() -> bidTypeFromExt(bid))
.or(() -> bidTypeFromAdm(bid.getAdm()))
.or(() -> bidTypeFromImp(bid, impIdToImp))
.orElseThrow(() -> new PreBidException("unable to determine media type for bid %s on imp %s"
.formatted(bid.getId(), bid.getImpid())));
}
private static Optional<BidType> bidTypeFromMtype(Integer mtype) {
return Optional.ofNullable(switch (mtype) {
case 1 -> BidType.banner;
case 2 -> BidType.video;
case 4 -> BidType.xNative;
case null, default -> null;
});
}
private static Optional<BidType> bidTypeFromExt(Bid bid) {
return Optional.ofNullable(bid.getExt())
.map(ext -> ext.get("hypelab"))
.map(hypelab -> hypelab.get("creative_type"))
.filter(JsonNode::isTextual)
.map(JsonNode::asText)
.map(creativeType -> switch (creativeType) {
case "display" -> BidType.banner;
case "video" -> BidType.video;
default -> null;
});
}
private static Optional<BidType> bidTypeFromAdm(String adm) {
return StringUtils.startsWith(StringUtils.trimToEmpty(adm), "<VAST")
? Optional.of(BidType.video)
: Optional.empty();
}
private static Optional<BidType> bidTypeFromImp(Bid bid, Map<String, Imp> impIdToImp) {
return impIdToImp.containsKey(bid.getImpid())
? Optional.of(BidderUtil.getBidType(bid, impIdToImp))
: Optional.empty();
}
| } | ||
|
|
||
| outgoingExt.addProperty("source", mapper.mapper().valueToTree(SOURCE)); | ||
| outgoingExt.addProperty("provider_version", mapper.mapper().valueToTree(pbsVersion())); |
Collaborator
There was a problem hiding this comment.
I see the difference with GO version. You didn't append prebid-server@ prefix
| return switch (StringUtils.defaultString(creativeType)) { | ||
| case "display" -> BidType.banner; | ||
| case "video" -> BidType.video; | ||
| default -> null; |
Collaborator
There was a problem hiding this comment.
GO version have native case:
case "native":
return openrtb_ext.BidTypeNative, true, nil
Comment on lines
+210
to
+212
| if (impIdToImp.containsKey(bid.getImpid())) { | ||
| return BidderUtil.getBidType(bid, impIdToImp); | ||
| } |
Collaborator
There was a problem hiding this comment.
GO doesn't support multi-media imps: mediaTypeCount == 1
| hype: ~ | ||
| meta-info: | ||
| maintainer-email: sdk@hypelab.com | ||
| app-media-types: [] |
Collaborator
There was a problem hiding this comment.
No need to declare empty app-media-types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔧 Type of changes
✨ What's the context?
This PR adds the HypeLab bid adapter to Prebid Server Java.
The adapter supports site banner, native, and video inventory. It accepts
property_slugandplacement_slugbidder params, forwards eligible OpenRTB 2.6 requests to HypeLab, adds HypeLab display manager metadata, and maps HypeLab bid responses back into Prebid bid types.🧠 Rationale behind the change
HypeLab needs a dedicated adapter because the request is not just a raw OpenRTB pass-through. The adapter validates required bidder params, sets
tagidfromplacement_slug, preserves the HypeLab bidder ext, adds provider metadata, and resolves response bid type frommtype,ext.hypelab.creative_type, VAST markup, or the original impression media type.🔎 New Bid Adapter Checklist
🧪 Test plan
How do you know the changes are safe to ship to production?
/openrtb2/auctionpath and HypeLab adapter configuration../mvnw -Dtest=HypeLabBidderTest testsuccessfully.HypeLabBidder: 96% instruction coverage and 97% line coverage.🏎 Quality check