Skip to content

Commit

Permalink
Merge pull request #487 from microsoft/andrueastman/DateAndPeriod
Browse files Browse the repository at this point in the history
Period and Duration aggregate type
  • Loading branch information
andrueastman authored Jul 19, 2023
2 parents 4deb493 + bc59326 commit b2d5b84
Show file tree
Hide file tree
Showing 24 changed files with 548 additions and 71 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

## [0.4.6] - 2023-07-20

### Added

- Adds the `PeriodAndDuration` type to aggregate `Period` and `Duration` serialization

### Changed

- Drops the `getPeriodValue` function in favour of `getPeriodAndDurationValue` in the serialization interface.
- Drops the `writePeriodValue` function in favour of `writePeriodAndDurationValue` in the serialization interface.

## [0.4.5] - 2023-06-27

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ public ApiException(@Nonnull final Throwable cause) {
@Nonnull
private ResponseHeaders responseHeaders = new ResponseHeaders();

/** Gets the HTTP response headers for the error response */
/**
* Gets the HTTP response headers for the error response
* @return The response headers collections from the failed response.
*/
@Nonnull
public ResponseHeaders getResponseHeaders() {
return new ResponseHeaders(responseHeaders);
}

/** Sets the HTTP response headers for the error response */
/**
* Sets the HTTP response headers for the error response
* @param responseHeaders The response headers collections to set.
*/
public void setResponseHeaders(@Nonnull ResponseHeaders responseHeaders) {
Objects.requireNonNull(responseHeaders);
this.responseHeaders = new ResponseHeaders(responseHeaders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
class CaseInsensitiveMap implements Map<String, Set<String>>{
private final HashMap<String, HashSet<String>> internalMap = new HashMap<>();

/**
* Formats the string to lower case
* @param key string to normalize to lower case
* @return The normalized string
*/
protected String normalizeKey(@Nonnull final String key) {
Objects.requireNonNull(key);
return key.toLowerCase(Locale.ROOT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

import com.microsoft.kiota.serialization.Parsable;
import com.microsoft.kiota.serialization.ParsableFactory;

/**
* The {@code ResponseHandler} implementation to handle native response objects
*/
public class NativeResponseHandler implements ResponseHandler {
private Object value;
private HashMap<String, ParsableFactory<? extends Parsable>> errorMappings;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
package com.microsoft.kiota;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
import java.time.Duration;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Collections;
import java.util.Objects;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;

import static java.time.temporal.ChronoUnit.YEARS;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.time.temporal.ChronoUnit.NANOS;


/**
* The aggregate type for {@code Period} and {@code Duration }
*/
@Immutable
public final class PeriodAndDuration implements TemporalAmount, Comparable<PeriodAndDuration>, Serializable {

/**
* A constant for a duration of zero.
*/
public static final PeriodAndDuration ZERO = new PeriodAndDuration(Period.ZERO, Duration.ZERO);

/**
* The period.
*/
private final Period period;

/**
* Gets the period section of the type.
* @return the period section
*/
@Nonnull
public Period getPeriod() {
return period;
}

/**
* The duration.
*/
private final Duration duration;
/**
* Gets the duration section of the type.
* @return the duration section
*/
@Nonnull
public Duration getDuration() {
return duration;
}

/**
* Non-public Constructor for PeriodAndDuration
* @param period The {@code Period} component of the aggregate type
* @param duration The {@code Duration } component of the aggregate type
*/
private PeriodAndDuration(@Nonnull Period period, @Nonnull Duration duration) {
Objects.requireNonNull(period, "parameter period cannot be null");
Objects.requireNonNull(duration, "parameter duration cannot be null");
this.period = period;
this.duration = duration;
}

/**
* Creates an instance based on a period and duration.
* @param period the {@code Period}, not null
* @param duration the {@code Duration}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration of(@Nonnull Period period, @Nonnull Duration duration) {
Objects.requireNonNull(period, "parameter period cannot be null");
Objects.requireNonNull(duration, "parameter duration cannot be null");
return new PeriodAndDuration(period, duration);
}

/**
* Creates an instance based on a period.
* @param period the {@code Period}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration ofPeriod(@Nonnull Period period) {
Objects.requireNonNull(period, "parameter period cannot be null");
return new PeriodAndDuration(period, Duration.ZERO);
}

/**
* Creates an instance based on a duration.
* @param duration the {@code Duration}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration ofDuration(@Nonnull Duration duration) {
Objects.requireNonNull(duration, "parameter duration cannot be null");
return new PeriodAndDuration(Period.ZERO, duration);
}

/**
* @param stringValue the {@code String} parse from.
* @return parsed instance of {@code PeriodAndDuration}
*/
@Nonnull
public static PeriodAndDuration parse(@Nonnull String stringValue) {
Objects.requireNonNull(stringValue, "parameter stringValue cannot be null");

if (stringValue.substring(0,3).contains("PT")) {// it is only a duration value as it starts with 'PT', '+PT' or, '-PT'
return PeriodAndDuration.ofDuration(Duration.parse(stringValue));
}
int timePosition = stringValue.indexOf("T");
if (timePosition < 0) {// only a period value as there is no time component
return PeriodAndDuration.ofPeriod(Period.parse(stringValue));
}

String sign = "";
if (stringValue.charAt(0) == '-') {
sign = "-";
}// no need for checking the `+` sign as this is the default

Period period = Period.parse(stringValue.substring(0, timePosition));//sign will be passed and parsed
Duration duration = Duration.parse(sign + "P" + stringValue.substring(timePosition));// pass the negative if need be
return PeriodAndDuration.of(period, duration);
}

/**
* @param periodAndDuration the {@code PeriodAndDuration} for which to compare to
* @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(@Nonnull PeriodAndDuration periodAndDuration) {
Objects.requireNonNull(periodAndDuration, "parameter periodAndDuration cannot be null");

if(this.equals(periodAndDuration)) {
return 0;//they are the same/equal
}

if(this.period.equals(periodAndDuration.getPeriod())) {// same period so just compare the durations
return this.duration.compareTo(periodAndDuration.getDuration());
}

// just check if the difference in the period is negative as this makes the duration moot
if(this.period.minus(periodAndDuration.getPeriod()).isNegative()) {
return -1;//this period is smaller. So duration won't count
}else {
return 1;
}
}

/**
* @param unit the {@code TemporalUnit} for which to return the value
* @return the long value of the unit
*/
@Override
public long get(@Nonnull TemporalUnit unit) {
Objects.requireNonNull(unit, "parameter unit cannot be null");
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case YEARS:
return period.getYears();
case MONTHS:
return period.getMonths();
case DAYS:
return period.getDays();
case HOURS:
return duration.toHours() % 24;
case MINUTES:
return duration.toMinutes() % 60;
case SECONDS:
return duration.getSeconds() % 60;
case NANOS:
return duration.getNano();
default:
break;
}
}
throw new UnsupportedTemporalTypeException("Unsupported TemporalUnit of type: " + unit);
}

private static final List<TemporalUnit> UNITS = Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, NANOS));
/**
* @return the List of TemporalUnits; not null
*/
@Override
public List<TemporalUnit> getUnits() {
return new ArrayList<>(UNITS);
}

/**
* @param temporal the temporal object to add the amount to, not null
* @return an object of the same observable type with the addition made, not null
*/
@Override
public Temporal addTo(@Nonnull Temporal temporal) {
Objects.requireNonNull(temporal, "parameter temporal cannot be null");
return temporal.plus(period).plus(duration);//just add everything up
}

/**
* @param temporal the temporal object to subtract the amount from, not null
* @return an object of the same observable type with the subtraction made, not null
*/
@Override
public Temporal subtractFrom(@Nonnull Temporal temporal) {
Objects.requireNonNull(temporal, "parameter temporal cannot be null");
return temporal.minus(period).minus(duration);//just subtract everything up
}

/**
* Returns a string representation of the instance in the ISO-8601 format 'PnYnMnDTnHnMnS'.
* @return the period in ISO-8601 string format
*/
@Override
public String toString() {
if (period.isZero()) {
return duration.toString();
}
if (duration.isZero()) {
return period.toString();
}
//simply concatenate and drop the first `P` in the duration
return period + duration.toString().substring(1);
}

/**
* Gets the hashcode for the object.
* @return The hashCode of the object
*/
@Override
public int hashCode() {
return period.hashCode() + duration.hashCode();
}
/**
* Checks if this instance is equal to the specified {@code PeriodAndDuration}.
* @param otherPeriodAndDuration the other Object, null returns false
* @return true if the other otherPeriodAndDuration is equal to this one
*/
@Override
public boolean equals(Object otherPeriodAndDuration) {
if(this == otherPeriodAndDuration) {
return true; // same instance
}

if (otherPeriodAndDuration instanceof PeriodAndDuration) {
PeriodAndDuration otherInstance = (PeriodAndDuration) otherPeriodAndDuration;
return this.period.equals(otherInstance.period) && this.duration.equals(otherInstance.duration);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
/**
* This annotation allows mapping between the query parameter name in the template and the property name in the class.
*/
@Retention(RetentionPolicy.RUNTIME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ public class RequestHeaders extends Headers {
public RequestHeaders() {
super();
}

/** Copy constructor */

/**
* Copy constructor
* @param requestHeaders The request headers to initialize with.
*/
public RequestHeaders(@Nonnull RequestHeaders requestHeaders) {
super(requestHeaders);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.Period;


import javax.annotation.Nonnull;
Expand Down Expand Up @@ -305,8 +304,8 @@ else if(valueClass.equals(LocalDate.class))
writer.writeLocalDateValue(null, (LocalDate)value);
else if(valueClass.equals(LocalTime.class))
writer.writeLocalTimeValue(null, (LocalTime)value);
else if(valueClass.equals(Period.class))
writer.writePeriodValue(null, (Period)value);
else if(valueClass.equals(PeriodAndDuration.class))
writer.writePeriodAndDurationValue(null, (PeriodAndDuration)value);
else {
final RuntimeException result = new RuntimeException("unknown type to serialize " + valueClass.getName());
span.recordException(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ public ResponseHeaders() {
super();
}

/** Copy constructor */
/**
* Copy constructor
* @param responseHeaders The response headers to initialize with.
*/
public ResponseHeaders(@Nonnull ResponseHeaders responseHeaders) {
super(responseHeaders);
}
Expand Down
Loading

0 comments on commit b2d5b84

Please sign in to comment.